{"components":{"schemas":{"AccountingAccount":{"additionalProperties":false,"properties":{"id":{"description":"The account's id in the accounting system, when the mapping holds one (QbAccountId).","type":"string"},"name":{"description":"The account name in the mapping (QbAccount).","type":"string"},"type":{"description":"The account type the mapping recorded (QbAccountType).","type":"string"}},"required":[],"type":"object"},"AccountingChecks":{"additionalProperties":false,"properties":{"departmentGrossVsSales":{"description":"The department totals' gross less salesExTax, when they are available; normally within cents. Dollars, exact to the cent.","type":"number"},"difference":{"description":"tendersNet - salesExTax - tax - paidOnAccount: expected 0.00. Dollars, exact to the cent.","type":"number"},"groupGrossVsSales":{"description":"The register groups' gross less salesExTax; normally within cents. Dollars, exact to the cent.","type":"number"},"paidOnAccount":{"description":"Payments received on account. Dollars, exact to the cent.","type":"number"},"paidOut":{"description":"Paid-outs (shown for reference; a paid-out balances itself). Dollars, exact to the cent.","type":"number"},"salesExTax":{"description":"Taxable + non-taxable + tax-exempt sales. Dollars, exact to the cent.","type":"number"},"startingCash":{"description":"Starting cash recorded in the register (inside the register's money taken, not inside the tenders; shown for reference). Dollars, exact to the cent.","type":"number"},"tax":{"description":"All tax collected. Dollars, exact to the cent.","type":"number"},"tendersNet":{"description":"The payments on tickets less the change: what came into the drawer, gross of paid-outs. Dollars, exact to the cent.","type":"number"}},"required":["tendersNet","salesExTax","tax","paidOnAccount","paidOut","startingCash","difference"],"type":"object"},"AccountingDay":{"additionalProperties":false,"properties":{"businessDay":{"format":"date","type":"string"},"checks":{"$ref":"#/components/schemas/AccountingChecks"},"cogsSource":{"description":"Where COGS comes from: the department totals when available, else the register's group totals.","enum":["departments","groups"],"type":"string"},"departmentTotals":{"description":"available: every log that sold has department totals; partial: some do; not_enabled: none (the store has not turned on department totals at its registers).","enum":["available","partial","not_enabled"],"type":"string"},"externalId":{"description":"The store-day's stable id: ENTERPRISE-STORE-YYYYMMDD from the POS's own codes. It never changes.","type":"string"},"lines":{"description":"The day's totals as labeled lines; a zero line is omitted.","items":{"$ref":"#/components/schemas/AccountingLine"},"type":"array"},"logs":{"items":{"$ref":"#/components/schemas/AccountingLog"},"type":"array"},"revision":{"description":"16 hex characters that change whenever any number behind the day changes. Upsert by externalId when (externalId, revision) is new.","type":"string"},"status":{"description":"final: every log of the day is closed and the day is over at the store. provisional: a log is still open, or the day is not over. no_activity: no register log that day.","enum":["final","provisional","no_activity"],"type":"string"},"store":{"$ref":"#/components/schemas/AccountingStore"}},"required":["businessDay","status","externalId","revision","store","logs","departmentTotals","lines"],"type":"object"},"AccountingJournalEntry":{"additionalProperties":false,"properties":{"adjustment":{"additionalProperties":false,"properties":{"account":{"description":"Where the difference was posted (Sales/Adjustment); null when nothing was posted.","oneOf":[{"$ref":"#/components/schemas/AccountingAccount"},{"type":"null"}]},"amount":{"description":"The difference between debits and credits before the adjustment. Dollars, exact to the cent.","type":"number"},"side":{"enum":["debit","credit"],"type":"string"}},"required":["amount","account"],"type":"object"},"businessDay":{"format":"date","type":"string"},"class":{"description":"The mapping's Info/ItemClassName value.","type":"string"},"entity":{"description":"The mapping's Info/CustomerName value.","type":"string"},"externalId":{"description":"The store-day's stable id (as on the summary); upsert by it.","type":"string"},"lines":{"items":{"$ref":"#/components/schemas/AccountingJournalLine"},"type":"array"},"logs":{"items":{"$ref":"#/components/schemas/AccountingLog"},"type":"array"},"mapping":{"additionalProperties":false,"properties":{"updatedAt":{"format":"date-time","type":"string"},"version":{"description":"A hash of the mapping's items.","type":"string"}},"required":["version"],"type":"object"},"memo":{"description":"Register sales \u003cday\u003e, logs \u003cnumbers\u003e.","type":"string"},"revenueView":{"enum":["total_incl_tax","tax_status","department","department_tax_status"],"type":"string"},"revision":{"description":"16 hex characters over the posted lines, the entity, the class, the status and the mapping version.","type":"string"},"skipped":{"description":"Non-zero lines no mapping posts; never dropped silently.","items":{"$ref":"#/components/schemas/AccountingSkipped"},"type":"array"},"status":{"description":"Post ready entries only. provisional: the day is not final; needs_attention: a blocking warning; no_activity: no register log that day.","enum":["ready","provisional","needs_attention","no_activity"],"type":"string"},"store":{"$ref":"#/components/schemas/AccountingStore"},"totals":{"additionalProperties":false,"properties":{"credit":{"description":"Total credits. Dollars, exact to the cent.","type":"number"},"debit":{"description":"Total debits. Dollars, exact to the cent.","type":"number"}},"required":["debit","credit"],"type":"object"},"warnings":{"items":{"$ref":"#/components/schemas/AccountingWarning"},"type":"array"}},"required":["businessDay","externalId","revision","status","store","memo","logs","lines","totals","adjustment","skipped","warnings","mapping"],"type":"object"},"AccountingJournalLine":{"additionalProperties":false,"properties":{"account":{"$ref":"#/components/schemas/AccountingAccount"},"credit":{"description":"Credit amount (0 on a debit line). Dollars, exact to the cent.","type":"number"},"debit":{"description":"Debit amount (0 on a credit line). Dollars, exact to the cent.","type":"number"},"defaulted":{"description":"The department had no mapping of its own and posted through Dept: \u003cUndefined\u003e.","type":"boolean"},"department":{"description":"The department of a department line.","type":"string"},"entity":{"additionalProperties":false,"properties":{"id":{"description":"QbEntityId.","type":"string"},"name":{"description":"QbName.","type":"string"},"type":{"description":"QbEntityType.","type":"string"}},"required":[],"type":"object"},"key":{"$ref":"#/components/schemas/AccountingKey"},"kind":{"description":"The line's kind (as on the summary line), or adjustment.","type":"string"},"lineNumber":{"description":"1-based line number.","type":"integer"},"memo":{"description":"The line's memo.","type":"string"}},"required":["lineNumber","key","kind","account","debit","credit","memo"],"type":"object"},"AccountingJournalResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"entries":{"description":"One journal entry per store-day, in day order. One row is one store-day. Any range may be asked for (no limit on its span); one answer holds at most limit store-days (default 100) and a nextCursor for the rest. The store is read in several jobs for a long range, and an answer that reaches the request's reading budget holds the days read so far and a nextCursor, so a long range never turns into a timeout. A day after the store's own today is never returned. Every day of the range is a row, a day without a register log included (status no_activity): a missing day is never confused with a failed read.","items":{"$ref":"#/components/schemas/AccountingJournalEntry"},"type":"array"},"from":{"format":"date","type":"string"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"maxAdjustment":{"description":"The adjustment limit applied. Dollars, exact to the cent.","type":"number"},"nextCursor":{"description":"Pass as cursor (with the same from and to) to read the next days; empty when the range is done.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"to":{"format":"date","type":"string"}},"required":["requestId","from","to","maxAdjustment","entries","nextCursor","generatedAt","source"],"type":"object"},"AccountingKey":{"additionalProperties":false,"properties":{"category":{"description":"The mapping category, exactly as TisWin3's QuickBooks mapping names it: Sales, Departments, Departments Taxable, Departments NonTaxable, Departments COGS, Departments Inventory, Taxes, Payments, COGS or Paid Out.","type":"string"},"name":{"description":"The mapping name: NetSales, Taxable, NonTaxable, TaxExempt, Tax1, Tax2, PdAcnt, COGS, COGS Inevntory Asset (the real key, misspelled), Paid Out, Paid Out Credit, a tender's name, or Dept: \u003cDEPARTMENT\u003e (Dept: \u003cUndefined\u003e for a blank department).","type":"string"}},"required":["category","name"],"type":"object"},"AccountingLine":{"additionalProperties":false,"properties":{"amount":{"description":"The amount with the register's sign (a net return is negative). Dollars, exact to the cent.","type":"number"},"changeDeducted":{"description":"The change given, taken off this tender's total (the store's change tender). Dollars, exact to the cent.","type":"number"},"cost":{"description":"The group's cost of goods sold. Dollars, exact to the cent.","type":"number"},"count":{"description":"How many payments made a tender's total.","type":"number"},"department":{"description":"The department of a department line, upper-cased (\u003cUndefined\u003e for a blank one).","type":"string"},"gross":{"description":"The group's gross sales. Dollars, exact to the cent.","type":"number"},"group":{"description":"The register group (0-9) of an info_group_sales line.","type":"integer"},"key":{"$ref":"#/components/schemas/AccountingKey"},"kind":{"description":"What the line is. Kinds starting with info_ are informational and never mapped: info_returns, info_discounts, info_group_sales, info_paid_out_tenders, info_account_tenders, info_other_tenders, info_billed_to_account, info_change, info_paper_bags, info_order_deposits, info_non_revenue.","type":"string"},"net":{"description":"Non-revenue net. Dollars, exact to the cent.","type":"number"},"returns":{"description":"Non-revenue returns. Dollars, exact to the cent.","type":"number"},"revenueView":{"description":"On a revenue line: the view it belongs to. The four views describe the same money; a journal entry uses exactly one.","enum":["total_incl_tax","tax_status","department","department_tax_status"],"type":"string"},"side":{"description":"The natural accounting side, a suggestion; the mapping decides in the journal entries.","enum":["debit","credit"],"type":"string"},"source":{"description":"The tender source: C payments on tickets, O paid-outs, A payments on the account screen.","type":"string"},"tenderCode":{"description":"The tender's PayList code(s) on a tender line.","type":"string"},"tenderName":{"description":"The tender's name on an informational tender line.","type":"string"}},"required":["kind"],"type":"object"},"AccountingLog":{"additionalProperties":false,"properties":{"closed":{"description":"Whether the log is closed (its Z printed). An open log is included in the totals and makes the day provisional.","type":"boolean"},"endedAt":{"description":"When the log ended (UTC).","format":"date-time","type":"string"},"logNumber":{"description":"The register log number.","type":"integer"},"register":{"description":"The register code.","type":"string"},"startedAt":{"description":"When the log started (UTC).","format":"date-time","type":"string"}},"required":["register","logNumber","closed"],"type":"object"},"AccountingMappingItem":{"additionalProperties":false,"properties":{"category":{"description":"Category.","type":"string"},"inActive":{"description":"The item is switched off.","type":"boolean"},"name":{"description":"Name.","type":"string"},"qbAccount":{"description":"QbAccount.","type":"string"},"qbAccountId":{"description":"QbAccountId.","type":"string"},"qbAccountType":{"description":"QbAccountType.","type":"string"},"qbEntityId":{"description":"QbEntityId.","type":"string"},"qbEntityType":{"description":"QbEntityType.","type":"string"},"qbName":{"description":"QbName (the value of an Info key).","type":"string"},"qbType":{"description":"Debit or Credit (Debit when the mapping sets none).","type":"string"}},"required":["category","name","qbType"],"type":"object"},"AccountingMappingKey":{"additionalProperties":false,"properties":{"alternative":{"description":"A revenue key of a view the mapping does not use (it posts another view of the same money), or a tax key when the mapping posts sales including tax: it needs no mapping.","type":"boolean"},"category":{"description":"The mapping category.","type":"string"},"mapped":{"description":"The key posts: its item is active and names an account.","type":"boolean"},"mapping":{"oneOf":[{"$ref":"#/components/schemas/AccountingMappingItem"},{"type":"null"}]},"name":{"description":"The mapping name.","type":"string"},"seenInLast90Days":{"description":"The key carried a non-zero amount on some day of the window.","type":"boolean"},"source":{"description":"Why the key is listed: a fixed key, one per tender, one per department in each department category, or held by the mapping only.","enum":["fixed","tender","department","mapping"],"type":"string"}},"required":["category","name","source","mapping","mapped","seenInLast90Days"],"type":"object"},"AccountingMappingResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"keys":{"items":{"$ref":"#/components/schemas/AccountingMappingKey"},"type":"array"},"mappedRevenueViews":{"description":"The revenue views the mapping posts; more than one counts revenue twice.","items":{"type":"string"},"type":"array"},"mapping":{"additionalProperties":false,"properties":{"items":{"description":"How many items the mapping holds.","type":"integer"},"present":{"description":"The store holds a mapping.","type":"boolean"},"updatedAt":{"format":"date-time","type":"string"},"version":{"description":"A hash of the mapping's items (as on the journal entries).","type":"string"}},"required":["present","items"],"type":"object"},"requestId":{"type":"string"},"seenUnmapped":{"description":"Keys that moved money in the window and have no mapping (alternatives not counted): what still needs one before go-live.","type":"integer"},"settings":{"additionalProperties":false,"properties":{"changeTender":{"description":"The tender code change is given in.","type":"string"},"exportMode":{"description":"TisWin3's QuickBooks sales export mode (Journal Entry or Sales Receipt); its mapping screen lists the department keys only in Journal Entry mode.","type":"string"},"useFsDeps":{"description":"Whether the registers write department totals (FsData.UseFsDeps); the department views need it.","type":["boolean","null"]}},"required":["useFsDeps","exportMode"],"type":"object"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"store":{"$ref":"#/components/schemas/AccountingStore"},"window":{"additionalProperties":false,"properties":{"from":{"format":"date","type":"string"},"to":{"format":"date","type":"string"}},"required":["from","to"],"type":"object"}},"required":["requestId","store","settings","mapping","mappedRevenueViews","window","keys","seenUnmapped","generatedAt","source"],"type":"object"},"AccountingSkipped":{"additionalProperties":false,"properties":{"amount":{"description":"The amount not posted. Dollars, exact to the cent.","type":"number"},"department":{"description":"The department of a department line.","type":"string"},"key":{"$ref":"#/components/schemas/AccountingKey"},"kind":{"description":"The line's kind.","type":"string"}},"required":["key","kind","amount"],"type":"object"},"AccountingStore":{"additionalProperties":false,"properties":{"posEnterpriseCode":{"description":"The store's enterprise code in its POS (FsData EnterpriseID).","type":"string"},"posStoreCode":{"description":"The store's own code in its POS (FsData StoreID).","type":"string"}},"required":[],"type":"object"},"AccountingSummariesResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"days":{"description":"One row per store-day, in day order. One row is one store-day. Any range may be asked for (no limit on its span); one answer holds at most limit store-days (default 100) and a nextCursor for the rest. The store is read in several jobs for a long range, and an answer that reaches the request's reading budget holds the days read so far and a nextCursor, so a long range never turns into a timeout. A day after the store's own today is never returned. Every day of the range is a row, a day without a register log included (status no_activity): a missing day is never confused with a failed read.","items":{"$ref":"#/components/schemas/AccountingDay"},"type":"array"},"from":{"format":"date","type":"string"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor (with the same from and to) to read the next days; empty when the range is done.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"to":{"format":"date","type":"string"}},"required":["requestId","from","to","days","nextCursor","generatedAt","source"],"type":"object"},"AccountingWarning":{"additionalProperties":false,"properties":{"blocking":{"description":"A blocking warning keeps the entry from ready (needs_attention).","type":"boolean"},"code":{"enum":["revenue_counted_twice","revenue_not_mapped","tax_counted_twice","cogs_counted_twice","unbalanced","adjustment_over_limit","departments_not_enabled","skipped_lines","defaulted_departments","cogs_from_groups","suspicious_account_type"],"type":"string"},"detail":{"description":"What was found.","type":"string"}},"required":["code","blocking"],"type":"object"},"BillingMeta":{"additionalProperties":false,"description":"The charge for this response as billing priced it. Present on every billed success response; absent on free endpoints and on error responses, which are never charged.","properties":{"baseCost":{"description":"Credits the endpoint costs with up to includedFields response fields.","type":"integer"},"decision":{"description":"Billing's decision for the call, for example allowed_included, allowed_overage, allowed_sandbox, or house. On a call the store pays for under its approval it is allowed (allowed_sandbox for a test key): whether the call fell in the store's included credits is the store's. Such a call also has no X-Credits-Remaining header or trailer, since the balance is the store's; X-Credits-Charged and this block say what the call cost.","type":"string"},"extraFieldCredits":{"description":"max(0, fieldCount - includedFields) * extraFieldCost.","type":"integer"},"fieldCount":{"description":"Number of fields the request resolved to (the standard set when fields is omitted). Two names for one field (unitsPerCase and the deprecated upc) count once.","type":"integer"},"includedFields":{"description":"Fields covered by baseCost; 0 for fixed-cost endpoints.","type":"integer"},"mode":{"description":"live for a production key; test for a sandbox (cd_test_) key.","enum":["live","test"],"type":"string"},"priceSource":{"description":"Which layer priced the call: default (the endpoint's list price, as published in this document), plan (the store's plan carries its own price for this endpoint), subscription (a price agreed for this store), or house (a CompuDime-owned integration, priced at zero). store is the legacy value while billing reports no layer.","enum":["default","plan","subscription","house","store"],"type":"string"},"pricingVersion":{"description":"Billing's pricing version the call was priced under; also in X-Pricing-Version.","type":"string"},"quantity":{"description":"How many units this call was charged for: 1 on a per-request endpoint; on a per-row endpoint the rows the response carries, on a per-page endpoint the pages of 100 rows they fill, rounded up (0 when the page came back empty and nothing was charged). Absent when billing reports no unit.","type":"integer"},"totalCredits":{"description":"baseCost + extraFieldCredits: the price of one unit. On a per-request endpoint (unit request or order, or no unit reported) it is the credits this call was charged, also in X-Credits-Charged; on a per-row or per-page endpoint (unit row or page) the charge is totalCredits times quantity, which X-Credits-Charged reports.","type":"integer"},"unit":{"description":"The pricing unit the call was priced by: request or order (the price once per call, the default), row (the price for each row the call returns), or page (the price for each page of 100 rows the call returns, rounded up); CompuDime chooses it per endpoint. Absent when billing reports no unit.","enum":["request","order","row","page"],"type":"string"}},"required":["baseCost","fieldCount","includedFields","extraFieldCredits","totalCredits","decision","pricingVersion"],"type":"object"},"BrandListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"brands":{"description":"One page of brands in a stable order that is not alphabetical (the POS's row id, or on a list built from the products a hash of the value); sort by name yourself for display.","items":{"$ref":"#/components/schemas/PosBrand"},"maxItems":500,"type":"array"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","brands","nextCursor","generatedAt","source"],"type":"object"},"Capability":{"additionalProperties":true,"properties":{"displayName":{"type":"string"},"enabled":{"type":"boolean"},"endpointFamilies":{"items":{"type":"string"},"type":"array"},"id":{"type":"string"},"lockedReason":{"type":"string"},"scopes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"CapabilityListResponse":{"additionalProperties":true,"properties":{"accessLevel":{"description":"The key's integration access level. own: the customer reads return only the customers linked to the integration (the customers its own orders landed on in the store's POS); all: the store's whole customer file. x-compudime-access-level on each operation says what the level changes there.","enum":["own","all"],"type":"string"},"capabilities":{"items":{"$ref":"#/components/schemas/Capability"},"type":"array"},"store":{"additionalProperties":true,"properties":{"displayName":{"type":"string"},"sandbox":{"description":"true when the key's store is the demo store (CompuDime Demo Market): its data is invented, only test keys may call it, and it is never billed. Absent for a real store.","type":"boolean"},"storeId":{"type":"string"}},"type":"object"}},"type":"object"},"CatalogSnapshot":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"format":"date-time","type":"string"},"productCount":{"type":"integer"},"snapshotId":{"type":"string"},"sourceRelayJobId":{"type":"string"}},"type":"object"},"CategoryListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"categories":{"description":"One page of rows: the departments, then the categories, then the sub-categories, each list in a stable order that is not alphabetical (the POS's row id, or on a list built from the products a hash of the value); sort by name yourself for display.","items":{"$ref":"#/components/schemas/PosCategory"},"maxItems":500,"type":"array"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","categories","nextCursor","generatedAt","source"],"type":"object"},"CostBreakdown":{"additionalProperties":false,"properties":{"baseCost":{"description":"Credits the endpoint costs with up to includedFields response fields.","type":"integer"},"extraFieldCost":{"description":"Credits per field beyond includedFields.","type":"integer"},"extraFieldCredits":{"description":"max(0, fieldCount - includedFields) * extraFieldCost.","type":"integer"},"fieldCount":{"description":"Number of fields the request resolved to (the standard set when fields is omitted). Two names for one field (unitsPerCase and the deprecated upc) count once.","type":"integer"},"includedFields":{"description":"Fields covered by baseCost; 0 for fixed-cost endpoints.","type":"integer"},"pricingVersion":{"description":"Billing's pricing version the quote was priced under; the real call stamps the same value in X-Pricing-Version.","type":"string"},"totalCredits":{"description":"baseCost + extraFieldCredits: what the real call would reserve.","type":"integer"}},"required":["baseCost","fieldCount","includedFields","extraFieldCost","extraFieldCredits","totalCredits","pricingVersion"],"type":"object"},"CustomerAccount":{"additionalProperties":false,"description":"A customer's house-account position at the store. Sensitive: returned only when fields names account and the store owner allowed sensitive customer fields for the integration.","properties":{"balance":{"description":"Amount the customer owes; negative is a credit on account.","type":"number"},"creditLimit":{"description":"House-account credit limit; 0 when none is set.","type":"number"},"current":{"description":"Part of the balance not yet 30 days old.","type":"number"},"lastPaymentAmount":{"description":"Amount of the last payment on account; 0 when there is none.","type":"number"},"lastPaymentDate":{"description":"Date of the last payment on account; absent when there is none.","format":"date","type":"string"},"lastPurchaseDate":{"description":"Date of the last purchase; absent when there is none.","format":"date","type":"string"},"over120":{"description":"Part of the balance over 120 days old.","type":"number"},"over30":{"description":"Part of the balance over 30 days old.","type":"number"},"over60":{"description":"Part of the balance over 60 days old.","type":"number"},"over90":{"description":"Part of the balance over 90 days old.","type":"number"}},"required":["balance","creditLimit","current","over30","over60","over90","over120","lastPaymentAmount"],"type":"object"},"CustomerListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"customers":{"description":"One page in a stable order (POS customer id, then phone). The register's anonymous walk-in and remote-customer placeholder accounts are never listed.","items":{"$ref":"#/components/schemas/PosCustomer"},"maxItems":200,"type":"array"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","customers","nextCursor","generatedAt","source"],"type":"object"},"CustomerLookupResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"customers":{"items":{"$ref":"#/components/schemas/PosCustomer"},"maxItems":5,"type":"array"},"found":{"type":"boolean"},"requestId":{"type":"string"}},"required":["requestId","found","customers"],"type":"object"},"CustomerResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"customer":{"$ref":"#/components/schemas/PosCustomer"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","customer","generatedAt","source"],"type":"object"},"DeliveryRoute":{"additionalProperties":false,"description":"One delivery route of the store with two counts. Counts only: never a list of the customers or the invoices behind them.","properties":{"customers":{"description":"Customers assigned to the route. The register's anonymous walk-in and remote-customer placeholder accounts are never counted.","minimum":0,"type":"integer"},"openInvoices":{"description":"How many open invoices the route carries, exactly as the store's POS agent counts them; the API does not recompute it. The rule today: an invoice is open when its due date is today or later (the store's calendar) and the POS has recorded no delivery-done time for it; the POS status is not consulted. A pickup order never receives a delivery-done time, so it counts as open until its due date has passed. CompuDime is reviewing this rule and may refine it at the store agent; the field, its type and its meaning (open invoices on the route) stay as published. Absent, never 0, when the store's POS cannot answer the rule.","minimum":0,"type":"integer"},"route":{"description":"The route as the store spells it; two spellings that differ only in case are one route.","type":"string"}},"type":"object"},"DeliveryRouteListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"requestId":{"type":"string"},"routes":{"description":"The store's routes in route order. Not paged: one answer carries every route, up to 500.","items":{"$ref":"#/components/schemas/DeliveryRoute"},"maxItems":500,"type":"array"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"truncated":{"description":"True when the store has more than 500 routes and the rest were left out.","type":"boolean"}},"required":["requestId","routes","truncated","generatedAt","source"],"type":"object"},"EstimateResponse":{"additionalProperties":false,"description":"A free, priced quote for exactly this request. Returned in place of the normal 200 body when estimate=true; nothing is reserved and nothing reaches the store.","properties":{"estimate":{"$ref":"#/components/schemas/CostBreakdown"},"fields":{"description":"The resolved field projection the quote was priced for (field-priced endpoints only).","items":{"type":"string"},"type":"array"},"priceSource":{"description":"Which layer priced the quote: default (the endpoint's list price, as published in this document), plan (the store's plan carries its own price for this endpoint), subscription (a price agreed for this store), or house (a CompuDime-owned integration, priced at zero). store is the legacy value while billing reports no layer.","enum":["default","plan","subscription","house","store"],"type":"string"},"quantity":{"description":"Per-row and per-page endpoints only: on unit row the page bound of exactly this request (its effective limit, or the day count of a daily range), the most rows the real call can return; on unit page the pages of 100 rows that bound fills, rounded up.","type":"integer"},"requestId":{"type":"string"},"totalCredits":{"description":"Per-row and per-page endpoints only: estimate.totalCredits times quantity, the most the real call can cost. It is an upper bound: the real call settles down to the rows it returns (or the pages they fill), and an empty page costs nothing.","type":"integer"},"unit":{"description":"Present only when billing prices this endpoint per row or per page: estimate then prices ONE row (or one page of 100 rows), and quantity and totalCredits give the call. Absent on a per-request endpoint, whose estimate is the whole call.","enum":["row","page"],"type":"string"}},"required":["requestId","estimate"],"type":"object"},"HealthStatus":{"additionalProperties":true,"properties":{"ok":{"type":"boolean"}},"type":"object"},"InvoiceListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"invoices":{"description":"One page of invoice headers in a stable order (invoice id, then customer id). A list row never carries lines, linesTruncated or delivery; read the invoice for those.","items":{"$ref":"#/components/schemas/PosInvoice"},"maxItems":200,"type":"array"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","invoices","nextCursor","generatedAt","source"],"type":"object"},"InvoiceResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"invoice":{"$ref":"#/components/schemas/PosInvoice"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","invoice","generatedAt","source"],"type":"object"},"LiveProduct":{"additionalProperties":false,"description":"One live product as the register resolves it right now. Sale prices are the effective prices (a percent-off sale is already applied), so salePrice / caseSalePrice / packageSalePrice are what the register charges while the matching *Active flag is true and 0 otherwise.","properties":{"activePrice":{"description":"What the register charges now: the sale price while a sale window is open, else price; on a price-embedded barcode, the price decoded from the barcode.","type":"number"},"autoTare":{"description":"The register applies the tare automatically.","type":"boolean"},"brand":{"type":"string"},"casePrice":{"description":"Regular case price (for unitsPerCase units).","type":"number"},"caseSaleActive":{"description":"A case sale is in its window right now.","type":"boolean"},"caseSalePrice":{"description":"Effective case sale price while caseSaleActive, else 0.","type":"number"},"category":{"type":"string"},"department":{"type":"string"},"description":{"type":"string"},"foodStamp":{"description":"SNAP / food-stamp eligible.","type":"boolean"},"inactive":{"description":"Flagged inactive in the product file (PrdMstr.InActive). The register still sells an inactive item.","type":"boolean"},"lastModifiedUtc":{"description":"When the product's row in the store's product file last changed (PrdMstr.UpdatedOn, stamped by the store's database on every write to the row, reported in UTC), read at the moment of the call; the same value as lastModifiedUtc on /v1/products. null when the store could not read it within the lookup's time budget, and until the store's agent reports it; the lookup itself still answers.","format":"date-time","type":["string","null"]},"lastSold":{"description":"The day the register last finished a sale with this item on it (PrdMstr.LastSold, a date without a time, the store's calendar day). Register sales only: the register stamps it on each item of a completed sale ticket with a nonzero quantity on its line, so a voided line, a voided, held or training ticket, an account charge and an order or delivery invoice never stamp it; a return rung on a sale ticket does. null when the item has never been stamped (or the store turned the stamp off) and until the store's agent reports it. Read at the moment of the call. null as well when the store could not read it within the lookup's time budget; the lookup itself still answers.","format":"date","type":["string","null"]},"matchField":{"description":"The POS field that matched: Prdmstr-\u003eCode, PrdAlias-\u003eAliasCode, Prdmstr-\u003eCaseCode or Prdmstr-\u003ePrdctSku; empty only when the POS sent no label.","type":"string"},"matchType":{"description":"How the code resolved, as the POS labels it: Exact or Not Exact (product code, with or without check-digit normalization), Alias Exact / Alias Not Exact, CaseCode Exact / CaseCode Not Exact, SKU Exact / SKU Not Exact; empty only when the POS sent no label.","type":"string"},"matchedCode":{"description":"The base product code that answered; equals productCode.","type":"string"},"noSale":{"description":"The register refuses to sell the item.","type":"boolean"},"onHand":{"description":"Current on-hand quantity; null when the store has never counted or received the item. Reported as is, including negative values.","type":["number","null"]},"pack":{"type":"string"},"packagePrice":{"description":"Regular price for packageQty units; 0 when the item has no package price.","type":"number"},"packageQty":{"description":"Units the package price covers; 0 when none.","type":"integer"},"packageSaleActive":{"description":"A package sale is in its window right now.","type":"boolean"},"packageSalePrice":{"description":"Effective price for packageSaleQty units while packageSaleActive, else 0.","type":"number"},"packageSaleQty":{"description":"Units the package sale price covers; 0 unless packageSaleActive.","type":"integer"},"price":{"description":"Regular unit price.","type":"number"},"priceEmbedded":{"description":"The code scanned carried its own price or weight; activePrice came from the barcode.","type":"boolean"},"productCode":{"description":"The resolved base product code (Prdmstr.Code).","type":"string"},"saleActive":{"description":"A unit sale is in its window right now.","type":"boolean"},"salePrice":{"description":"Effective unit sale price while saleActive, else 0.","type":"number"},"scale":{"description":"Sold by weight.","type":"boolean"},"size":{"type":"string"},"smallDescription":{"type":"string"},"subCategory":{"type":"string"},"tare":{"description":"Tare weight for scale items (0 when none).","type":"number"},"taxable":{"description":"Taxable.","type":"boolean"},"unitsPerCase":{"description":"Units per case (PrdMstr.UPC). Not a barcode.","type":"integer"},"upc":{"deprecated":true,"description":"Deprecated: use unitsPerCase, which carries the same value. upc keeps working and is not removed before a later, announced date. Units per case.","type":"integer"},"wic":{"description":"WIC eligible.","type":"boolean"}},"type":"object"},"MeResponse":{"additionalProperties":true,"description":"Who the calling key is: its display prefix, mode (live or test) and kind (genie for cd_ keys, compuconnect for cc_ keys); its integration (capability, access level, billing class); its store; for each resource the key can read, the fields it may request and the ones an omitted fields returns; its per-key rate limit; and, for the store's own keys, the store's credits for the month, as GET /v1/usage/current reports them without the per-endpoint breakdown. A key your organization holds for a store (a developer's key under the owner's approval, for instance) never sees the store's plan or credits: credits is left out, creditsNote says its calls are billed to your organization (or to the store, when the owner chose to pay), and usageUrl links your organization's usage at https://account.compudime.com/usage. Never the key itself. When billing cannot be read the answer is still 200, with credits left out and creditsNote saying so. Free; a good first call.","properties":{"credits":{"$ref":"#/components/schemas/UsageSummary"},"creditsNote":{"description":"Present when credits is absent, and says why: the store's credits could not be read (the rest of the answer is current), the store is the demo store, or the key is held by your organization rather than the store, so its calls are billed to your organization (or to the store, when its owner chose to pay) and the store's plan and credits are not shown to it.","type":"string"},"fieldPolicy":{"additionalProperties":true,"description":"One entry per resource the key can read today, listing the operations that read it with exactly these fields. fields is every name the key may put in fields (fields=* returns all of them except namedOnlyFields); defaultFields is what an omitted fields returns under today's pricing; namedOnlyFields are sensitive fields the store owner granted this integration, returned only when the request names them. source policy: the integration's pinned field policy (policyId) decides the fields; source catalog: the resource's published field catalog does. Empty when the store has not enabled the key's capability (GET /v1/capabilities).","properties":{"policyId":{"description":"The integration's pinned field policy.","type":"string"},"resources":{"items":{"additionalProperties":true,"properties":{"defaultFields":{"description":"What an omitted fields returns today.","items":{"type":"string"},"type":"array"},"endpoints":{"description":"The operation ids that read the resource with these fields.","items":{"type":"string"},"type":"array"},"fields":{"description":"Every name the key may request.","items":{"type":"string"},"type":"array"},"namedOnlyFields":{"description":"Sensitive fields granted to this integration, returned only when named.","items":{"type":"string"},"type":"array"},"resource":{"description":"The field catalog id (x-compudime-field-catalog.resource on the operations).","type":"string"},"source":{"description":"policy: the pinned field policy decides the fields; catalog: the resource's published field catalog does.","enum":["policy","catalog"],"type":"string"}},"required":["resource","endpoints","source","fields","defaultFields"],"type":"object"},"type":"array"},"rowScope":{"description":"The pinned row scope: the rows the key is limited to on the reads that honour it (see the Scoped API keys guide). Absent: every row of the store.","items":{"additionalProperties":false,"properties":{"field":{"type":"string"},"op":{"enum":["eq","in","prefix"],"type":"string"},"values":{"items":{"type":"string"},"type":"array"}},"type":"object"},"type":"array"},"version":{"description":"The pinned policy's version, as fieldPolicyVersion on the product answers.","type":"integer"}},"required":["policyId","version","resources"],"type":"object"},"integration":{"additionalProperties":true,"properties":{"accessLevel":{"description":"The integration's access level, as GET /v1/capabilities returns it.","enum":["own","all"],"type":"string"},"billingClass":{"description":"house: a CompuDime-owned integration, metered at zero (priceSource house); charged: every other integration.","enum":["charged","house"],"type":"string"},"capabilities":{"description":"The capabilities the key carries: capabilityId for a cd_ key; for a cc_ key every capability CompuConnect lists for it (other CompuDime APIs' included).","items":{"type":"string"},"type":"array"},"capabilityId":{"description":"The capability this integration reads under.","type":"string"},"displayName":{"type":"string"},"integrationId":{"description":"The integration the key reads through; problem bodies name it too.","type":"string"},"note":{"description":"Present on a cc_ key that carries more than one Public API capability: each reads through an integration of its own, and this answer describes the one named in capabilityId.","type":"string"}},"required":["integrationId","displayName","capabilityId","capabilities","accessLevel","billingClass"],"type":"object"},"key":{"additionalProperties":true,"properties":{"kind":{"description":"genie for a cd_ key, compuconnect for a cc_ key (issued at account.compudime.com).","enum":["genie","compuconnect"],"type":"string"},"mode":{"description":"test: the key's calls draw on the monthly sandbox allowance of the organization that pays for them and are never charged; live: they are billed to that organization's plan (the store's, or a developer's under a store approval).","enum":["live","test"],"type":"string"},"note":{"description":"Present on a test key: its calls are never charged.","type":"string"},"prefix":{"description":"The key's display prefix (cd_live_, cd_test_, or the first 12 characters of a cc_ key), as the console and the request logs show it. Never more of the key.","type":"string"}},"required":["prefix","mode","kind"],"type":"object"},"rateLimit":{"additionalProperties":true,"description":"The per-key limit every authenticated call passes, free ones included (see Rate limits). Billed calls are also held to the store plan's own per-minute ceiling.","properties":{"burst":{"type":"integer"},"requestsPerMinute":{"type":"integer"}},"type":"object"},"requestId":{"type":"string"},"store":{"additionalProperties":true,"properties":{"displayName":{"type":"string"},"sandbox":{"description":"true when the key's store is the demo store (CompuDime Demo Market): its data is invented, only test keys may call it, and it is never billed. Absent for a real store.","type":"boolean"},"storeId":{"type":"string"}},"required":["storeId","displayName"],"type":"object"},"usageUrl":{"description":"Present on a key your organization holds for a store: where your organization's own usage is, https://account.compudime.com/usage.","type":"string"}},"required":["requestId","key","integration","store","fieldPolicy"],"type":"object"},"MixMatchBogo":{"additionalProperties":false,"description":"One BOGO setting of a mix and match group, reported as data. The API never applies a BOGO (appliedByApi is always false): an order line of a group with a running BOGO is refused, and no runningNow includes one.","properties":{"amountOff":{"description":"Amount taken off each discounted item's price.","type":"number"},"appliedByApi":{"description":"Always false.","enum":[false],"type":"boolean"},"buyQuantity":{"description":"Items to buy.","type":"integer"},"getQuantity":{"description":"Items that get the discount.","type":"integer"},"maxGetItemPrice":{"description":"Only items priced at most this get the discount.","type":"number"},"maxGetQuantity":{"description":"At most this many discounted items per ticket.","type":"integer"},"minBuyItemPrice":{"description":"Only items priced at least this count toward buyQuantity.","type":"number"},"percentOff":{"description":"Percent taken off each discounted item.","type":"number"},"window":{"$ref":"#/components/schemas/PromotionWindow"}},"required":["buyQuantity","getQuantity","appliedByApi"],"type":"object"},"MixMatchGroup":{"additionalProperties":false,"description":"One mix and match group of the store with its members.","properties":{"bogo":{"description":"The group's BOGO settings, as data.","items":{"$ref":"#/components/schemas/MixMatchBogo"},"type":"array"},"description":{"description":"The group's description.","type":"string"},"groupId":{"description":"The group id.","type":"string"},"memberCount":{"description":"How many members the group has.","type":"integer"},"members":{"description":"The members in product code order, at most 1000.","items":{"$ref":"#/components/schemas/MixMatchMember"},"maxItems":1000,"type":"array"},"membersTruncated":{"description":"Present and true when the group has more members than the 1000 one answer carries.","type":"boolean"},"runningNow":{"description":"True when a member pools right now; false when every member was evaluated and none does; absent otherwise.","type":"boolean"}},"required":["groupId","memberCount","members"],"type":"object"},"MixMatchGroupResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"discountsOnByDefault":{"description":"The store's registers give deal prices on every ticket unless a cashier turns discounts off (true), or only on tickets where a cashier turns them on (false). Absent when the store's registers are not all set the same way.","type":"boolean"},"evaluatedAt":{"$ref":"#/components/schemas/PromotionClock"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"mixMatchGroup":{"$ref":"#/components/schemas/MixMatchGroup"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","mixMatchGroup","evaluatedAt","generatedAt","source"],"type":"object"},"MixMatchMember":{"additionalProperties":false,"description":"One member of a mix and match group; runningNow says whether it pools right now (a code that is not a product, or a product the register cannot sell, never does).","properties":{"bogoMember":{"description":"The member takes part in the group's BOGO.","type":"boolean"},"brand":{"description":"The product's brand.","type":"string"},"category":{"description":"The product's category.","type":"string"},"department":{"description":"The product's department.","type":"string"},"description":{"description":"The product's description.","type":"string"},"pooled":{"description":"As on a promotion's mixMatch.","type":"boolean"},"productCode":{"description":"The member's product code.","type":"string"},"qualifyingDeals":{"items":{"enum":["sale","package","packageSale","caseSale"],"type":"string"},"type":"array"},"runningNow":{"description":"Whether it pools at evaluatedAt; absent when a store rule decides or the data cannot be evaluated exactly.","type":"boolean"},"status":{"description":"At evaluatedAt: running (applied now), notNow (within its dates, but its time of day or weekdays exclude this moment; a mix and match membership whose qualifying deals are not on), upcoming (begins after today), ended (will never apply again; only an activeOn read of a past day returns one), storeRule (a store-written rule decides; not evaluated), undetermined (the store's data cannot be evaluated exactly; see undeterminedReason).","enum":["running","notNow","upcoming","ended","storeRule","undetermined"],"type":"string"},"storeRule":{"description":"That rule's name.","type":"string"},"storeRuleDecides":{"description":"A store-written rule decides.","type":"boolean"},"undeterminedReason":{"description":"Why it could not be evaluated exactly.","type":"string"}},"required":["productCode","pooled","qualifyingDeals","status"],"type":"object"},"OnHandListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"rows":{"description":"One page in product code order. A product with no on-hand row at the store (never counted or received) is absent, which is not the same as zero.","items":{"$ref":"#/components/schemas/OnHandRow"},"maxItems":500,"type":"array"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","rows","nextCursor","generatedAt","source"],"type":"object"},"OnHandRow":{"additionalProperties":false,"description":"One on-hand quantity: a product at the store as a whole, or at one inventory location.","properties":{"location":{"description":"The inventory location; empty on a store total.","type":"string"},"onHand":{"description":"Quantity on hand exactly as the POS stores it. Negative values are real (the store sold more than it received or counted) and are never clamped to zero.","type":"number"},"productCode":{"description":"The store product code the quantity belongs to.","type":"string"},"updatedAt":{"description":"When the POS last changed the quantity (UTC). Absent when the store's POS keeps no such time.","format":"date-time","type":"string"}},"type":"object"},"OrderAccepted":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"createdAt":{"format":"date-time","type":"string"},"dispatchState":{"description":"Where the order is on its way to the store's POS: pending_pos_adapter (accepted and queued, not in the POS yet), dispatched (it landed in the POS), parked (it could not be sent or the POS refused it; the order.parked webhook says why), or simulated (a test key's order: validated, never sent to the store, and final).","type":"string"},"externalOrderId":{"type":"string"},"fulfillment":{"$ref":"#/components/schemas/OrderFulfillment","description":"Where the order stands in the store (picking, out for delivery, delivered, and so on), once the order landed and the store answered. Absent before that. It is the last field; fields=fulfillment selects it. The order reads are flat-priced: selecting it changes no charge. On the 202 answer only a replay of an order the store already answered for carries it."},"invoice":{"$ref":"#/components/schemas/OrderInvoiceLink","description":"The POS invoice the order became, named by the feed identity the store stamped on it, once the store reported the order landed (dispatchState dispatched). Absent before that. fields=invoice selects it. On the 202 answer only a replay of an order that already landed carries it."},"orderId":{"description":"CompuDime's id for the order. A test key's simulated order has an id that starts with test_; a live order's id never does.","type":"string"},"orderMethod":{"description":"The method the order was created with (delivery when it was created with a shipTo and no orderMethod). Absent when the order named none: the store's default delivery method applies when it reaches the POS.","enum":["pickup","delivery"],"type":"string"},"requestId":{"type":"string"},"shipTo":{"$ref":"#/components/schemas/OrderShipTo","description":"The delivery address the order was created with, normalized (trimmed, state upper-cased, phone as 10 digits). Absent when the order carries none."},"status":{"description":"accepted for every order the API took, a live key's and a test key's alike; dispatchState says where it went.","type":"string"},"storeDiscount":{"$ref":"#/components/schemas/OrderStoreDiscount","description":"The customer's discount the store took off the lines it priced (register rule), once the order is dispatched. Absent before that and whenever none applied (the cash account, a customer without a discount, the order_screen rule, or no line priced by the store). It follows storePrices; fields=storeDiscount selects it. Flat-priced like storePrices. On the 202 answer only a replay of an order that already landed carries it."},"storePrices":{"description":"What the store charged for each line the order sent without a unitPrice, in line order, once the order is dispatched (dispatchState dispatched). Absent before that, and absent when every line carried its own unitPrice (such an order reads exactly as before). It follows invoice; fields=storePrices selects it. The order reads are flat-priced: selecting it changes no charge. On the 202 answer only a replay of an order that already landed carries it.","items":{"$ref":"#/components/schemas/OrderStorePrice"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"required":["requestId","orderId","externalOrderId","status","dispatchState"],"type":"object"},"OrderCreateLine":{"additionalProperties":false,"properties":{"notes":{"type":"string"},"productCode":{"type":"string"},"quantity":{"minimum":1,"type":"integer"},"unitPrice":{"description":"The price per unit (per pound with a weight), a plain decimal (\"3.29\"). It lands on the POS invoice line as sent and is never repriced. Optional: a line without unitPrice (omitted, or an empty string) is priced by the store when the order is dispatched, under the store's price rule (the store owner sets it in the console, per store or per integration): register, the default, charges what the store's register charges, over the whole order: the regular price, sale prices with their limits, package prices (such as 3 for $5) and package sales, case prices, mix and match groups priced together, minimum purchases, scheduled price changes and the customer's contract price (found by the order's phone); order_screen charges what the store's own Customer Orders screen charges (the item's regular price, or the customer's dollar contract price; no sale, no deal). Lines without a unitPrice for the same product are priced as one register line. A deal the register charges as a line total that is not a whole number of cents per unit is posted as the same product at two unit prices a cent apart, or, at a store that does not allow the same product twice in one order, as the product at its regular price and an adjustment line carrying the saving; storePrices shows the line total and those parts. A line with a unitPrice is never repriced; it counts toward a minimum purchase at its own price. Under register, the customer the order lands on (by its phone) also gets the percent discount the store's register gives that customer, taken off the lines the store priced (never off a line with a unitPrice, which still counts toward the customer's minimum for the discount) and posted as savings lines without a product code, one per tax class; storeDiscount shows it. order_screen gives none, like the Customer Orders screen. The store refuses to price a line, and the order parks (dispatchState parked; the dispatchError starts [INVALID_LINE] and names the line, its code and the reason; send the order again with a unitPrice on that line) when: the register would price it together with a line you priced (the same product with a quantity deal, or the same mix and match group); the item is in a buy-one-get-one group; a sale is limited per customer; the customer's contract price is a percentage (register rule); a rule the store runs while pricing may change the line and what it does cannot be proven (the reason names the rule), or a scheduled price depends on a condition; the customer's discount cannot be determined with certainty (for example it depends on the age of the customer's balance, a password prompt, or how the order is paid); the store gives discounts by loyalty points; the item is sold by weight and the line has no weight, or the register prices a weighed item with a quantity deal; the item is sold by price-embedded labels, or the code carries its own price or weight; the item is not for sale, inactive, or the register asks for its price; the price is 0; the same product is on two lines at a store that may not allow it (send one line); on the order_screen rule, the store turned off automatic prices on customer orders (POS preference #348); or the store cannot determine the product, the customer, a setting or the price with certainty. A store agent or relay that does not price lines yet parks the order unsent with [AGENT_STORE_PRICING_UNSUPPORTED] or [RELAY_STORE_PRICING_UNSUPPORTED] (a line with a weight is gated the same way); it never lands at a zero price.","type":"string"},"weight":{"description":"Optional weight in pounds for an item sold by weight: a decimal string with at most three decimals, above 0 and at most 9999.999 (anything else is a free 400 before billing). The store books the weight as the line's quantity and prices it per pound: at unitPrice when you send one, else the store's price per pound. A weight is refused (the order parks with [INVALID_LINE]) when the item is not sold by weight, or when it has more decimals, or is larger, than the store's POS keeps on an invoice line (two decimals and 999.99 on current TisWin3 databases). A line for an item sold by weight that is sent without a unitPrice needs a weight. quantity stays required on every line; on a weighed line the POS books the weight, not the quantity.","pattern":"^[0-9]{1,4}(\\.[0-9]{1,3})?$","type":"string"}},"required":["productCode","quantity"],"type":"object"},"OrderCreateRequest":{"additionalProperties":false,"properties":{"customer":{"description":"A 10-digit North American phone number (formatting and a leading 1 are ignored) matches or creates the POS customer; any other value is written as the invoice's ship-to name, of which the POS keeps the first 35 characters, unless shipTo names the recipient.","type":"string"},"externalOrderId":{"type":"string"},"lines":{"items":{"$ref":"#/components/schemas/OrderCreateLine"},"minItems":1,"type":"array"},"notes":{"description":"Free text for the store; it lands in the POS invoice's Remark, which keeps the first 50 characters. Longer notes are accepted (not refused), but only those 50 reach the invoice.","type":"string"},"orderMethod":{"description":"How the customer gets the order. Optional: omit it (or send an empty string) and the store's own default delivery method applies, exactly as before this field existed; with a shipTo and no orderMethod the order is a delivery (the 202 and the reads then say delivery). pickup together with a shipTo is a free 400 (a pickup has no delivery address). Any other value is a free 400 before billing. On a replay of the same Idempotency-Key or externalOrderId the stored order keeps the method it was created with.","enum":["pickup","delivery"],"type":"string"},"shipTo":{"$ref":"#/components/schemas/OrderShipTo","description":"Optional delivery address. With it the order is a delivery; without it (or null) the order is exactly what it was before this field existed."}},"required":["externalOrderId","lines"],"type":"object"},"OrderFulfillment":{"additionalProperties":true,"description":"Where the order stands in the store, as CompuDime last read it from the store's POS. It appears once the order landed (dispatchState dispatched) and the store answered at least once, and is read again on a fixed schedule (every few minutes, set per deployment) until it is final (delivered, completed or canceled) or two weeks after the order was created. The store answers only when its CompuDime agent reads orders for the platform and the store has turned per-item data on at its POS; otherwise the order simply has no fulfillment. It never names a person (no picker, no driver) and carries no customer, address or money.","properties":{"canceledAt":{"description":"When CompuDime found the order gone from the POS. Absent unless canceled.","format":"date-time","type":"string"},"checkedAt":{"description":"When CompuDime last read the order's status from the store.","format":"date-time","type":"string"},"completedAt":{"description":"When CompuDime first saw an order that is not a delivery rung up at the register. Absent until then.","format":"date-time","type":"string"},"deliveredAt":{"description":"When the store recorded the delivery as done. Absent until then.","format":"date-time","type":"string"},"eta":{"description":"The delivery ETA the store recorded, a time of day on the store's own clock (HH:MM:SS, no date, no zone). Absent when there is none and once the order is final.","pattern":"^[0-9]{2}:[0-9]{2}:[0-9]{2}$","type":"string"},"outForDeliveryAt":{"description":"When a driver took the order. Absent until then.","format":"date-time","type":"string"},"pickedAt":{"description":"When picking was done. Absent until then.","format":"date-time","type":"string"},"picking":{"$ref":"#/components/schemas/OrderPickingProgress","description":"Picking progress over the order's lines as the POS keeps them. Absent when the store does not record it per line."},"state":{"description":"received: the invoice is in the POS and no step is recorded yet. picking: the store started picking. picked: picking is done (every line marked picked, the picker app marked the order complete, or the order screen's Filled box is ticked). out_for_delivery: a driver took the order. delivered: the store recorded the delivery as done (final). completed: an order that is not a delivery was rung up at the register, the customer checked out (final). canceled: the store deleted the order from its POS after CompuDime had seen it there, which is how the POS cancels an order (final). A state can move back when the store undoes a step (for example unticks Filled); a milestone already announced is not announced again.","enum":["received","picking","picked","out_for_delivery","delivered","completed","canceled"],"type":"string"},"updatedAt":{"description":"When the order reached state: the time the POS recorded for that step when it recorded one, else when CompuDime first saw the order in that state.","format":"date-time","type":"string"}},"required":["state","updatedAt","checkedAt"],"type":"object"},"OrderInvoiceLink":{"additionalProperties":false,"description":"The POS invoice a platform order became, named by the feed identity the store agent stamped on it: externalId and processorCode are the path value and the processorCode query of GET /v1/invoices/external/{externalId}. The link is a reference, not a grant: it is present whatever the calling key may read, and following it is an ordinary invoice read by feed identity (GET /v1/invoices/external/{externalId}?processorCode=) with that endpoint's own requirements: the sales-data capability and the sales.read scope, a key without a row scope, and the store's per-item data switch. An order-intake key carries only the order-intake capability, so it gets a free 403 capability_not_enabled (nothing reserved, nothing sent to the store); read the invoice with the same store's sales-data key. The store compares both values the way its POS stored them (current TisWin3 databases keep the first 25 characters of the external id and the first 10 of the processor code) and answers 409 invoice_ambiguous rather than guess when two invoices match; 404 invoice_not_found while the store has not turned the order into an invoice yet, or after it deleted it; 422 filter_unsupported at a store below TisWin3 database version 1.324, which keeps neither column. None of these is charged. The POS strips leading zeros from a feed's order id, so the lookup can miss an externalOrderId that starts with 0.","properties":{"externalId":{"description":"The order's externalOrderId, which the store wrote to the invoice's ExternalID.","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#@+-]{0,127}$","type":"string"},"processorCode":{"description":"CDAPI: followed by your integration id (at most 50 characters), which the store wrote to the invoice's ProcessorCode. Send it whole; the store cuts it the way its POS did.","pattern":"^[A-Za-z0-9][A-Za-z0-9 ._:#\u0026+@-]{0,49}$","type":"string"},"url":{"description":"GET /v1/invoices/external/{externalId}?processorCode= for this order as an absolute URL on the deployment's public base URL, both values already percent-encoded. Present when the deployment knows its public base URL, like a problem's docsUrl.","format":"uri","type":"string"}},"required":["externalId","processorCode"],"type":"object"},"OrderPickingProgress":{"additionalProperties":false,"description":"The order's lines as the POS keeps them and how many the store has picked (a line marked picked, or whose picked quantity reached its ordered quantity). Lines the store added (a savings line, a deposit) count too.","properties":{"lines":{"minimum":0,"type":"integer"},"pickedLines":{"minimum":0,"type":"integer"}},"required":["lines","pickedLines"],"type":"object"},"OrderShipTo":{"additionalProperties":false,"description":"Delivery address written on the POS invoice header. street, city, state and zip are required together; name (or firstName/lastName), street2 and phone are optional. Every part is trimmed; the limits apply after trimming and count characters. A value over its limit, a missing required part, a control character or pickup with a shipTo is a free 400 before billing whose detail names the field and its limit. The address is returned only to the integration that sent it (both order reads are scoped to it) and never in webhook bodies.","properties":{"city":{"description":"City (invoice ShipCity).","maxLength":35,"type":"string"},"firstName":{"description":"The recipient's first name. The POS stores lastName, a space and firstName as one ship-to name of at most 35 characters, so the two together must fit in 34.","maxLength":35,"type":"string"},"lastName":{"description":"The recipient's last name (see firstName).","maxLength":35,"type":"string"},"name":{"description":"The recipient as one value (invoice ShipName, 35 characters). Do not send it together with firstName or lastName.","maxLength":35,"type":"string"},"phone":{"description":"Delivery phone (invoice ShipTel): a 10-digit North American number. Spaces, dashes, dots, parentheses and a leading +1 or 1 are formatting and are stripped; it is stored and returned as the 10 digits. Without it the POS uses the customer's phone.","type":"string"},"state":{"description":"Two-letter state code (invoice ShipState); stored and returned upper-cased.","pattern":"^[A-Za-z]{2}$","type":"string"},"street":{"description":"Street address, first line (invoice ShipAdd1).","maxLength":35,"type":"string"},"street2":{"description":"Street address, second line (invoice ShipAdd2).","maxLength":35,"type":"string"},"zip":{"description":"ZIP code (invoice ShipZip): up to 10 characters of digits, spaces and dashes, starting and ending with a digit (08701, 08701-1234).","maxLength":10,"pattern":"^[0-9]([0-9 -]*[0-9])?$","type":"string"}},"required":["street","city","state","zip"],"type":"object"},"OrderStatus":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"createdAt":{"format":"date-time","type":"string"},"dispatchState":{"description":"Where the order is on its way to the store's POS: pending_pos_adapter (accepted and queued, not in the POS yet), dispatched (it landed in the POS), parked (it could not be sent or the POS refused it; the order.parked webhook says why), or simulated (a test key's order: validated, never sent to the store, and final).","type":"string"},"externalOrderId":{"type":"string"},"fulfillment":{"$ref":"#/components/schemas/OrderFulfillment","description":"Where the order stands in the store (picking, out for delivery, delivered, and so on), once the order landed and the store answered. Absent before that. It is the last field; fields=fulfillment selects it. The order reads are flat-priced: selecting it changes no charge. On the 202 answer only a replay of an order the store already answered for carries it."},"invoice":{"$ref":"#/components/schemas/OrderInvoiceLink","description":"The POS invoice the order became, named by the feed identity the store stamped on it, once the store reported the order landed (dispatchState dispatched). Absent before that. fields=invoice selects it. On the 202 answer only a replay of an order that already landed carries it."},"orderId":{"description":"CompuDime's id for the order. A test key's simulated order has an id that starts with test_; a live order's id never does.","type":"string"},"orderMethod":{"description":"The method the order was created with (delivery when it was created with a shipTo and no orderMethod). Absent when the order named none: the store's default delivery method applies when it reaches the POS.","enum":["pickup","delivery"],"type":"string"},"requestId":{"type":"string"},"shipTo":{"$ref":"#/components/schemas/OrderShipTo","description":"The delivery address the order was created with, normalized (trimmed, state upper-cased, phone as 10 digits). Absent when the order carries none."},"status":{"description":"accepted for every order the API took, a live key's and a test key's alike; dispatchState says where it went.","type":"string"},"storeDiscount":{"$ref":"#/components/schemas/OrderStoreDiscount","description":"The customer's discount the store took off the lines it priced (register rule), once the order is dispatched. Absent before that and whenever none applied (the cash account, a customer without a discount, the order_screen rule, or no line priced by the store). It follows storePrices; fields=storeDiscount selects it. Flat-priced like storePrices. On the 202 answer only a replay of an order that already landed carries it."},"storePrices":{"description":"What the store charged for each line the order sent without a unitPrice, in line order, once the order is dispatched (dispatchState dispatched). Absent before that, and absent when every line carried its own unitPrice (such an order reads exactly as before). It follows invoice; fields=storePrices selects it. The order reads are flat-priced: selecting it changes no charge. On the 202 answer only a replay of an order that already landed carries it.","items":{"$ref":"#/components/schemas/OrderStorePrice"},"type":"array"},"updatedAt":{"format":"date-time","type":"string"}},"required":["requestId","orderId","externalOrderId","status","dispatchState"],"type":"object"},"OrderStoreDiscount":{"additionalProperties":false,"description":"The percent discount the store's register gives the customer the order lands on (found by the order's phone), taken off the lines the store priced and posted on the invoice as savings lines without a product code, one per tax class of the discounted lines (usually one). The store's Customer Orders screen never applies a customer's discount by itself, so it is taken once. The register takes it only when the order's total is above the customer's minimum for the discount, and never off an item marked for no discount or, unless the store gives the discount on sale items too, off a line that got its own sale or deal.","properties":{"amount":{"description":"What the store took off, negative: the percent of base rounded half up to the cent.","pattern":"^-[0-9]{1,6}\\.[0-9]{2}$","type":"string"},"base":{"description":"The total of the store-priced lines that took the discount.","pattern":"^[0-9]{1,6}\\.[0-9]{2}$","type":"string"},"parts":{"description":"Present when the discount was posted as more than one savings line (lines of different tax classes took it); the parts add up to amount.","items":{"additionalProperties":false,"properties":{"kind":{"enum":["discount"],"type":"string"},"quantity":{"enum":["1"],"type":"string"},"unitPrice":{"description":"The savings line's price, negative.","pattern":"^-[0-9]{1,6}\\.[0-9]{2}$","type":"string"}},"required":["kind","quantity","unitPrice"],"type":"object"},"type":"array"},"percent":{"description":"The discount in percent, two decimals (\"10.00\").","pattern":"^[0-9]{1,3}\\.[0-9]{2}$","type":"string"},"priceRule":{"description":"The price rule the order was priced under.","enum":["register"],"type":"string"},"source":{"description":"customer: the customer's own discount.","enum":["customer"],"type":"string"}},"required":["source","priceRule","percent","base","amount"],"type":"object"},"OrderStorePrice":{"additionalProperties":false,"description":"What the store charged for one order line sent without a unitPrice. Store pricing: a line without unitPrice (omitted, or an empty string) is priced by the store when the order is dispatched, under the store's price rule (the store owner sets it in the console, per store or per integration): register, the default, charges what the store's register charges, over the whole order: the regular price, sale prices with their limits, package prices (such as 3 for $5) and package sales, case prices, mix and match groups priced together, minimum purchases, scheduled price changes and the customer's contract price (found by the order's phone); order_screen charges what the store's own Customer Orders screen charges (the item's regular price, or the customer's dollar contract price; no sale, no deal). Lines without a unitPrice for the same product are priced as one register line. A deal the register charges as a line total that is not a whole number of cents per unit is posted as the same product at two unit prices a cent apart, or, at a store that does not allow the same product twice in one order, as the product at its regular price and an adjustment line carrying the saving; storePrices shows the line total and those parts. A line with a unitPrice is never repriced; it counts toward a minimum purchase at its own price. Under register, the customer the order lands on (by its phone) also gets the percent discount the store's register gives that customer, taken off the lines the store priced (never off a line with a unitPrice, which still counts toward the customer's minimum for the discount) and posted as savings lines without a product code, one per tax class; storeDiscount shows it. order_screen gives none, like the Customer Orders screen. The store refuses to price a line, and the order parks (dispatchState parked; the dispatchError starts [INVALID_LINE] and names the line, its code and the reason; send the order again with a unitPrice on that line) when: the register would price it together with a line you priced (the same product with a quantity deal, or the same mix and match group); the item is in a buy-one-get-one group; a sale is limited per customer; the customer's contract price is a percentage (register rule); a rule the store runs while pricing may change the line and what it does cannot be proven (the reason names the rule), or a scheduled price depends on a condition; the customer's discount cannot be determined with certainty (for example it depends on the age of the customer's balance, a password prompt, or how the order is paid); the store gives discounts by loyalty points; the item is sold by weight and the line has no weight, or the register prices a weighed item with a quantity deal; the item is sold by price-embedded labels, or the code carries its own price or weight; the item is not for sale, inactive, or the register asks for its price; the price is 0; the same product is on two lines at a store that may not allow it (send one line); on the order_screen rule, the store turned off automatic prices on customer orders (POS preference #348); or the store cannot determine the product, the customer, a setting or the price with certainty. A store agent or relay that does not price lines yet parks the order unsent with [AGENT_STORE_PRICING_UNSUPPORTED] or [RELAY_STORE_PRICING_UNSUPPORTED] (a line with a weight is gated the same way); it never lands at a zero price.","properties":{"line":{"description":"The line's position in the order's lines, from 1.","minimum":1,"type":"integer"},"lineTotal":{"description":"What the store booked for the line: for a weighed line weight times unitPrice cut to the cent as its invoice keeps it (1.37 lb at 3.49 is 4.78); for a line the register rule priced, the register's line total (3 of a 3 for 5.00 deal is 5.00). Absent for a counted line priced under the order_screen rule.","pattern":"^[0-9]{1,6}\\.[0-9]{2}$","type":"string"},"parts":{"description":"Present when the line was posted as more than one invoice line: the same product at two unit prices a cent apart (the register's total over the units), or the product at its regular price and an adjustment line without a product code carrying the saving. The parts add up to lineTotal.","items":{"additionalProperties":false,"properties":{"kind":{"enum":["product","adjustment"],"type":"string"},"quantity":{"description":"Whole units; 1 for an adjustment.","pattern":"^[1-9][0-9]*$","type":"string"},"unitPrice":{"description":"The posted unit price; negative for a saving.","pattern":"^-?[0-9]{1,6}\\.[0-9]{2}$","type":"string"}},"required":["kind","quantity","unitPrice"],"type":"object"},"type":"array"},"priceRule":{"description":"The store's price rule the line was priced under: register (what the store's register charges) or order_screen (what the store's Customer Orders screen charges).","enum":["register","order_screen"],"type":"string"},"priceSource":{"description":"Where the price came from: regular (the item's regular price), scheduled (a scheduled price change in effect, register rule), sale (the sale price, register rule), contract (the customer's contract price), or the register's deal: package (a package price such as 3 for $5), package_sale, case (the case price for full cases), case_sale, mix (a mix and match group priced together).","enum":["regular","scheduled","sale","contract","package","package_sale","case","case_sale","mix"],"type":"string"},"productCode":{"description":"The line's productCode as the order sent it.","type":"string"},"unitPrice":{"description":"What the store charged per unit (per pound for a weighed line), a decimal string with two decimals; never 0. For a line posted in parts, the first part's price (lineTotal is the line's total).","pattern":"^[0-9]{1,6}\\.[0-9]{2}$","type":"string"},"weight":{"description":"For a weighed line: the weight in pounds the store booked, as its POS keeps it (\"1.37\"). Absent for other lines.","type":"string"}},"required":["line","productCode","unitPrice","priceSource","priceRule"],"type":"object"},"OrderWebhookData":{"additionalProperties":true,"description":"The order's state when the event was queued. It never carries the delivery address, the customer or a staff member's name. New keys may be added; ignore the ones you do not know.","properties":{"attempts":{"description":"How many dispatch attempts had failed for this order when the event was queued. It is not the number of tries: on order.dispatched the attempt that landed is not counted, so an order that landed on its first try reports 0. On order.parked it includes the failure that parked the order; an order the store's operator parked by hand counts only the failures before. The count is never reset, not even when the owner retries a parked order.","type":"integer"},"dispatchError":{"description":"Why dispatch stopped (order.parked); empty on order.dispatched.","type":"string"},"dispatchState":{"enum":["dispatched","parked"],"type":"string"},"externalOrderId":{"description":"Your own order id, as sent on POST /v1/orders.","type":"string"},"fulfillment":{"$ref":"#/components/schemas/OrderFulfillment","description":"Where the order stands in the store, the same object the order reads carry: on the fulfillment events (order.picked, order.out_for_delivery, order.delivered, order.completed, order.canceled) only, absent on order.dispatched and order.parked."},"invoice":{"$ref":"#/components/schemas/OrderInvoiceLink","description":"The POS invoice the order became, the same link the order reads carry: on order.dispatched and the fulfillment events (unless your externalOrderId is outside the shape the invoice read by feed identity accepts), absent on order.parked."},"orderId":{"description":"The platform order id (GET /v1/orders/{orderId}).","type":"string"},"posOrderRef":{"description":"The store's own reference for the landed order, exactly as the store agent reported it. Normally OrderExchange CDAPI:\u003cintegration id\u003e#\u003corder number\u003e: the order exchange key the order was posted under, with a number the agent derives from the platform order id. Only when the agent could already find the invoice as the order landed is it the POS invoice id instead. It is not a dependable invoice number: to read the invoice, follow invoice. Empty on order.parked.","type":"string"},"status":{"type":"string"}},"required":["orderId","externalOrderId","status","dispatchState","posOrderRef","dispatchError","attempts"],"type":"object"},"OrderWebhookEvent":{"additionalProperties":true,"description":"The body of one order webhook delivery. New keys may be added; ignore the ones you do not know.","properties":{"createdAt":{"description":"When the order changed state and the delivery was queued.","format":"date-time","type":"string"},"data":{"$ref":"#/components/schemas/OrderWebhookData"},"id":{"description":"The delivery id, also sent as X-CompuDime-Delivery. Retries and redeliveries carry the same id: deduplicate on it.","type":"string"},"type":{"description":"The event.","enum":["order.dispatched","order.parked","order.picked","order.out_for_delivery","order.delivered","order.completed","order.canceled"],"type":"string"}},"required":["id","type","createdAt","data"],"type":"object"},"PosBrand":{"additionalProperties":false,"description":"One brand the store's products carry. Each row is a value the store's products carry, exactly as they carry it in the matching product field (brand, department, category, subCategory, or one of a product's tags), with the number of products carrying it (inactive products included). The POS keeps these lists itself from the product file and removes a value when no product carries it any more; modifiedSince cannot report a removal, so re-read the whole list now and then to drop the values that are gone. The POS keeps them from TisWin3 database version 1.308 (GET /v1/store says the store's version). Where a store's POS keeps no such list, or keeps it empty, the list is built from the products themselves at the moment of the call: the same rows in the same shape, each count taken then, and as modifiedAt the newest change of any product carrying the value.","properties":{"modifiedAt":{"description":"When the POS last changed the row (UTC); what modifiedSince filters on. It changes with every product that gains or loses the value. On a list built from the products it is the newest change of any product carrying the value, so it also moves when such a product changes for another reason. Absent when the store's list keeps no modification time.","format":"date-time","type":"string"},"name":{"description":"The brand exactly as the products carry it in the product field brand.","type":"string"},"productCount":{"description":"The number of products carrying the value (inactive products included): the POS's own count as it keeps it, or, on a list built from the products, the count at the moment of the call. Absent when the store's list keeps no count.","type":"integer"}},"required":["name"],"type":"object"},"PosCategory":{"additionalProperties":false,"description":"One department, category or sub-category of the store. Each row is a value the store's products carry, exactly as they carry it in the matching product field (brand, department, category, subCategory, or one of a product's tags), with the number of products carrying it (inactive products included). The POS keeps these lists itself from the product file and removes a value when no product carries it any more; modifiedSince cannot report a removal, so re-read the whole list now and then to drop the values that are gone. The POS keeps them from TisWin3 database version 1.308 (GET /v1/store says the store's version). Where a store's POS keeps no such list, or keeps it empty, the list is built from the products themselves at the moment of the call: the same rows in the same shape, each count taken then, and as modifiedAt the newest change of any product carrying the value.","properties":{"modifiedAt":{"description":"When the POS last changed the row (UTC); what modifiedSince filters on. It changes with every product that gains or loses the value. On a list built from the products it is the newest change of any product carrying the value, so it also moves when such a product changes for another reason. Absent when the store's list keeps no modification time.","format":"date-time","type":"string"},"name":{"description":"The value exactly as the products carry it in that field.","type":"string"},"parent":{"description":"subCategory rows only: the category the sub-category belongs to (the POS keeps a sub-category per category, so one name may appear under two categories). Departments stand apart: the POS links no department to a category.","type":"string"},"productCount":{"description":"The number of products carrying the value (inactive products included): the POS's own count as it keeps it, or, on a list built from the products, the count at the moment of the call. Absent when the store's list keeps no count.","type":"integer"},"type":{"description":"Which list the row is on, which is also the product field its name fills.","enum":["department","category","subCategory"],"type":"string"}},"required":["type","name"],"type":"object"},"PosCustomer":{"additionalProperties":false,"properties":{"account":{"$ref":"#/components/schemas/CustomerAccount","description":"Customer list and read only, and only when fields names account for an integration the store owner allowed sensitive customer fields on. Never part of the default projection or of fields=*."},"addressLine1":{"type":"string"},"addressLine2":{"type":"string"},"cat":{"type":"string"},"city":{"type":"string"},"company":{"type":"string"},"custLevel":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"matchedOn":{"description":"Phone lookup only: the first phone column that matched.","enum":["tel","tel2","cell","fax"],"type":"string"},"modifiedAt":{"description":"Customer list and read only: when the POS last modified the customer (UTC). Absent when the store's POS keeps no modification time.","format":"date-time","type":"string"},"phones":{"items":{"$ref":"#/components/schemas/PosCustomerPhone"},"type":"array"},"posCustomerId":{"type":"string"},"postalCode":{"type":"string"},"state":{"type":"string"},"tagList":{"items":{"type":"string"},"type":"array"}},"required":["posCustomerId"],"type":"object"},"PosCustomerPhone":{"additionalProperties":false,"properties":{"kind":{"enum":["tel","tel2","cell","fax"],"type":"string"},"number":{"type":"string"}},"required":["kind","number"],"type":"object"},"PosInvoice":{"additionalProperties":false,"description":"One POS invoice (a customer order). A field whose column the store's POS lacks, or that the POS left blank, is absent. The invoice never carries who the customer is beyond the POS customer id: no name, phone, ship-to, remark or note.","properties":{"anonymousCustomer":{"description":"Present and true when the invoice belongs to the register's anonymous walk-in or remote-customer placeholder account, which is not a customer; absent otherwise.","type":"boolean"},"customerId":{"description":"The POS customer id (posCustomerId on the customer reads). Absent, with anonymousCustomer true, on an invoice of the register's anonymous walk-in or remote-customer placeholder account.","type":"string"},"date":{"description":"Invoice date (YYYY-MM-DD, the store's calendar).","format":"date","type":"string"},"delivery":{"$ref":"#/components/schemas/PosInvoiceDelivery","description":"Single-invoice reads only: the newest delivery-control record of the register tickets the order was rung up on (the POS keeps delivery records per register ticket); absent while the order has not been rung up or the store recorded no delivery for it, and from stores whose CompuDime agent predates this lookup."},"deliveryMethod":{"description":"The POS delivery method of the order, as the store configured it.","type":"string"},"deliveryTime":{"description":"Requested delivery time of day, store wall clock (HH:MM:SS).","type":"string"},"due":{"description":"Due date (YYYY-MM-DD, the store's calendar); what dueFrom / dueTo filter on.","format":"date","type":"string"},"externalId":{"description":"The placing system's own order id as the POS stored it (leading zeros stripped; its first 25 characters on current TisWin3 databases). Only at stores from TisWin3 database version 1.324.","type":"string"},"invoiceId":{"description":"The POS invoice id; pass it to GET /v1/invoices/{posInvoiceId}.","type":"string"},"lines":{"description":"Single-invoice reads only: the invoice's lines in the POS line order, at most 500. Always present on a single-invoice read that selects it (an empty array for an invoice without lines); never on a list row.","items":{"$ref":"#/components/schemas/PosInvoiceLine"},"maxItems":500,"type":"array"},"linesTruncated":{"description":"Single-invoice reads only: present and true when the invoice has more lines than the 500 one answer carries.","type":"boolean"},"modifiedAt":{"description":"When the POS last modified the invoice (UTC); what modifiedSince filters on. Absent when the store's POS keeps no modification time.","format":"date-time","type":"string"},"number":{"description":"The invoice number, at stores whose POS keeps one.","type":"string"},"orderDept":{"description":"The POS order department.","type":"string"},"orderNumber":{"description":"The store's running order number.","type":"string"},"payType":{"description":"The POS payment type of the order.","type":"string"},"processorCode":{"description":"The system that placed the order, as the POS stored it: its first 10 characters on current TisWin3 databases, so an order placed through POST /v1/orders reads CDAPI: plus the first four characters of the integration id. Only at stores from TisWin3 database version 1.324.","type":"string"},"route":{"description":"The delivery route (see GET /v1/delivery/routes).","type":"string"},"routeSeq":{"description":"The stop sequence on the route.","type":"string"},"source":{"description":"Which program or feed entered the order.","type":"string"},"status":{"description":"The POS status as the store wrote it (the POS writes Created, Picked, Completed and Processed; a store may use others).","type":"string"},"taxRate1":{"description":"The header's first tax percentage: what the POS multiplies a taxable1 line's amount by.","type":"number"},"taxRate2":{"description":"The header's second tax percentage.","type":"number"},"timeline":{"$ref":"#/components/schemas/PosInvoiceTimeline","description":"The order's fulfilment timeline; absent when the POS recorded no step."},"totals":{"$ref":"#/components/schemas/PosInvoiceTotals","description":"The header money columns as stored. Absent only when the store's POS has none of them."}},"required":["invoiceId"],"type":"object"},"PosInvoiceDelivery":{"additionalProperties":false,"description":"The newest delivery-control record of the register tickets the order was rung up on. The delivery address lines, the message to the customer, the geo coordinates and the delivery person's name are never part of it.","properties":{"eta":{"description":"Estimated time of arrival, store wall clock (HH:MM:SS).","type":"string"},"lastStatus":{"description":"The last delivery status the POS recorded.","type":"string"},"method":{"description":"Delivery method on the delivery record.","type":"string"},"route":{"description":"Delivery route on the delivery record.","type":"string"},"seq":{"description":"Stop sequence on the route.","type":"string"},"timeline":{"$ref":"#/components/schemas/PosInvoiceDeliveryTimeline","description":"The delivery record's own timeline; absent when no step was recorded."}},"type":"object"},"PosInvoiceDeliveryTimeline":{"additionalProperties":false,"description":"Steps the POS recorded on the delivery record (UTC); a step not recorded is absent.","properties":{"completed":{"description":"When the delivery was completed.","format":"date-time","type":"string"},"created":{"description":"When the delivery record was created.","format":"date-time","type":"string"},"delivered":{"description":"When the order was delivered.","format":"date-time","type":"string"},"deliveryDone":{"description":"When delivery was recorded as done.","format":"date-time","type":"string"},"filled":{"description":"When the order was filled.","format":"date-time","type":"string"},"lastStatusAt":{"description":"When lastStatus was recorded.","format":"date-time","type":"string"},"picked":{"description":"When picking was recorded.","format":"date-time","type":"string"},"printed":{"description":"When it was printed.","format":"date-time","type":"string"}},"type":"object"},"PosInvoiceLine":{"additionalProperties":false,"description":"One line of a POS invoice, as stored.","properties":{"amount":{"description":"Line amount as the POS stored it (for a weighed line the POS itself stores quantity x weight x price); never recomputed.","type":"number"},"cases":{"description":"Sold by the case (a flag, not a count).","type":"boolean"},"description":{"description":"The item description on the line.","type":"string"},"discountAmount":{"description":"Discount amount of the line. Normally absent: the POS does not store a per-line figure, and the API never derives one. Compute it yourself from amount, discountPercent, taxable1/2 and the header's taxRate1/2 if you need it.","type":"number"},"discountPercent":{"description":"The line's discount percentage, as stored.","type":"number"},"filled":{"description":"The line's picked flag.","type":"boolean"},"filledQuantity":{"description":"How much of the line was picked.","type":"number"},"lineId":{"description":"The POS line id.","type":"string"},"lineNumber":{"description":"The line's position on the order, as the POS shows it.","type":"string"},"netAmount":{"description":"Net amount of the line. Normally absent: the POS does not store a per-line figure, and the API never derives one. Compute it yourself from amount, discountPercent, taxable1/2 and the header's taxRate1/2 if you need it.","type":"number"},"price":{"description":"Unit price, as stored.","type":"number"},"productCode":{"description":"The store product code.","type":"string"},"quantity":{"description":"Quantity ordered, as stored (a stored null reads 0).","type":"number"},"scale":{"description":"A weighed item.","type":"boolean"},"taxAmount1":{"description":"First tax amount of the line. Normally absent: the POS does not store a per-line figure, and the API never derives one. Compute it yourself from amount, discountPercent, taxable1/2 and the header's taxRate1/2 if you need it.","type":"number"},"taxAmount2":{"description":"Second tax amount of the line. Normally absent: the POS does not store a per-line figure, and the API never derives one. Compute it yourself from amount, discountPercent, taxable1/2 and the header's taxRate1/2 if you need it.","type":"number"},"taxable1":{"description":"Whether the first tax applies to the line.","type":"boolean"},"taxable2":{"description":"Whether the second tax applies to the line.","type":"boolean"},"weightLb":{"description":"The weight factor of a weighed line.","type":"number"}},"required":["lineId","quantity","price","amount"],"type":"object"},"PosInvoiceTimeline":{"additionalProperties":false,"description":"Fulfilment steps the POS recorded on the invoice (UTC); a step not recorded is absent.","properties":{"created":{"description":"When the order was created.","format":"date-time","type":"string"},"deliveryDone":{"description":"When delivery was recorded as done. A pickup order never receives one.","format":"date-time","type":"string"},"filled":{"description":"When the order was filled.","format":"date-time","type":"string"},"outForDelivery":{"description":"When the order left for delivery.","format":"date-time","type":"string"},"picked":{"description":"When picking was recorded.","format":"date-time","type":"string"},"printed":{"description":"When the order was printed.","format":"date-time","type":"string"}},"type":"object"},"PosInvoiceTotals":{"additionalProperties":false,"description":"Header totals exactly as the POS stores them; a credit is negative and nothing is clamped or derived. A figure whose column the store lacks is absent; a stored null reads 0.","properties":{"billed":{"description":"Amount billed.","type":"number"},"discount":{"description":"The POS DISCOUNT column as stored. Its unit is unverified (the column is as wide as a percentage, not a dollar amount), so it is never converted; do not assume dollars.","type":"number"},"paid":{"description":"Amount paid.","type":"number"},"tax":{"description":"Tax on the invoice.","type":"number"}},"type":"object"},"PosPurchaseOrder":{"additionalProperties":false,"description":"One vendor purchase order of the store. A field whose column the store's POS lacks, or that the POS left blank, is absent. It never carries the salesperson, who entered it, a remark, the ship-to block or the vendor's contact details. The POS buys by the case: quantities count CASES (purchase units of unitsPerCase sell units each) and costs are the cost of ONE CASE, exactly as the POS stores them. The API derives nothing: no unit cost, no extended total and no outstanding quantity is computed, no sign is changed and nothing is clamped. Divide a case cost by unitsPerCase yourself if you need a unit cost.","properties":{"date":{"description":"Order date (YYYY-MM-DD, the store's calendar); what dateFrom / dateTo filter on.","format":"date","type":"string"},"discountPercent":{"description":"The order's discount percentage as stored: what the POS takes off each line's caseCostBeforeDiscount to arrive at its caseCost. Passed through; the API applies it to nothing.","type":"number"},"lines":{"description":"Single-order reads only: the order's lines in the POS line order, at most 500. Always present on a single-order read that selects it (an empty array for an order without lines); never on a list row.","items":{"$ref":"#/components/schemas/PosPurchaseOrderLine"},"maxItems":500,"type":"array"},"linesTruncated":{"description":"Single-order reads only: present and true when the order has more lines than the 500 one answer carries.","type":"boolean"},"number":{"description":"The store's running purchase-order number.","type":"string"},"purchaseOrderId":{"description":"The POS purchase order id; pass it to GET /v1/purchase-orders/{posPurchaseOrderId}, or as purchaseOrderId to GET /v1/receiving to find what received it.","type":"string"},"requestedShipDate":{"description":"Requested ship date (YYYY-MM-DD).","format":"date","type":"string"},"shipVia":{"description":"How the order is to ship, as the store wrote it.","type":"string"},"status":{"description":"The POS status as stored (the POS offers New, Open, Sent, Complete and Canceled).","type":"string"},"statusClass":{"description":"The class of status, which the status filter uses: open (New, Open or Sent: still to be received), received (Complete: imported into a receiving document) or canceled. Absent when the stored status is none of the five the POS offers. The POS has no partly-received status; how much arrived is on the receiving document.","enum":["open","received","canceled"],"type":"string"},"vendorCode":{"description":"The vendor's short code in the POS vendor list.","type":"string"},"vendorId":{"description":"The POS vendor id; what vendorId filters on.","type":"string"},"vendorName":{"description":"The vendor's name in the POS vendor list; absent when the vendor row is gone.","type":"string"},"vendorPoNumber":{"description":"The vendor's own reference for the order.","type":"string"}},"required":["purchaseOrderId"],"type":"object"},"PosPurchaseOrderLine":{"additionalProperties":false,"description":"One line of a vendor purchase order, as stored. The POS buys by the case: quantities count CASES (purchase units of unitsPerCase sell units each) and costs are the cost of ONE CASE, exactly as the POS stores them. The API derives nothing: no unit cost, no extended total and no outstanding quantity is computed, no sign is changed and nothing is clamped. Divide a case cost by unitsPerCase yourself if you need a unit cost.","properties":{"amount":{"description":"The line amount as the POS stored it (the POS stores orderedQuantity x caseCost); never recomputed.","type":"number"},"caseCost":{"description":"Cost of ONE CASE after the order's discountPercent, as stored. Not a unit cost.","type":"number"},"caseCostBeforeDiscount":{"description":"Cost of ONE CASE before the order's discount, as stored. Not a unit cost.","type":"number"},"costFlag":{"description":"The POS cost-flag letter of the line.","type":"string"},"description":{"description":"The item description on the line.","type":"string"},"discountAmount":{"description":"The line's discount amount, as stored.","type":"number"},"lineId":{"description":"The POS line id.","type":"string"},"lineNumber":{"description":"The line's position on the order, as the POS shows it.","type":"string"},"noDiscount":{"description":"The line is excluded from the order's discount.","type":"boolean"},"orderedQuantity":{"description":"Quantity ordered, in CASES, signed as stored (a return to the vendor is negative; a stored null reads 0).","type":"number"},"productCode":{"description":"The store product code.","type":"string"},"receivedQuantity":{"description":"A received quantity (in CASES) stored on the order line. Normally absent: the POS records a receipt on the receiving document, not here, so absent does NOT mean nothing was received. Read GET /v1/receiving?purchaseOrderId= for what arrived; the API never derives it.","type":"number"},"receivingId":{"description":"The receiving document the POS stored on the order line. Normally absent, for the same reason as receivedQuantity.","type":"string"},"unitsPerCase":{"description":"Sell units in one case, as the POS copied it from the product when the line was written.","type":"number"},"vendorItemCode":{"description":"The vendor's own item code.","type":"string"}},"required":["lineId","orderedQuantity"],"type":"object"},"PosReason":{"additionalProperties":false,"description":"One reason the store's register offers a cashier. The register lets a cashier type a reason of their own too, so a reason recorded on a sale may not be on this list. The POS keeps no list of void or inventory adjustment reasons.","properties":{"reason":{"description":"The reason exactly as the store wrote it.","type":"string"},"type":{"description":"discount: offered when a register or customer discount is given. return: offered when a return is rung.","enum":["discount","return"],"type":"string"}},"required":["type","reason"],"type":"object"},"PosReceiving":{"additionalProperties":false,"description":"One receiving document of the store: a vendor invoice / delivery, which is what moves stock and cost in the POS. Expense invoices (rent, utilities) are not receiving documents and never appear. A field whose column the store's POS lacks, or that the POS left blank, is absent. It never carries the salesperson, who entered it, a memo, remark or note, what was paid, the payment terms or the vendor's contact details. The POS buys by the case: quantities count CASES (purchase units of unitsPerCase sell units each) and costs are the cost of ONE CASE, exactly as the POS stores them. The API derives nothing: no unit cost, no extended total and no outstanding quantity is computed, no sign is changed and nothing is clamped. Divide a case cost by unitsPerCase yourself if you need a unit cost.","properties":{"billDue":{"description":"When the vendor's bill is due (YYYY-MM-DD).","format":"date","type":"string"},"businessDay":{"description":"The store business day the document belongs to (YYYY-MM-DD).","format":"date","type":"string"},"createdAt":{"description":"When the POS created the document (UTC).","format":"date-time","type":"string"},"date":{"description":"Document date (YYYY-MM-DD, the store's calendar); what dateFrom / dateTo filter on.","format":"date","type":"string"},"discountPercent":{"description":"The vendor's discount percentage on the document, as stored. Passed through; the API applies it to nothing.","type":"number"},"ignoreInventory":{"description":"The document did not move stock.","type":"boolean"},"inventoryLocation":{"description":"The inventory location the document received into.","type":"string"},"lines":{"description":"Single-document reads only: the document's lines in the POS line order, at most 500. Always present on a single-document read that selects it (an empty array for a document without lines, such as a quick delivery); never on a list row.","items":{"$ref":"#/components/schemas/PosReceivingLine"},"maxItems":500,"type":"array"},"linesTruncated":{"description":"Single-document reads only: present and true when the document has more lines than the 500 one answer carries.","type":"boolean"},"modifiedAt":{"description":"When the POS last modified the document (UTC); what modifiedSince filters on. Absent when the store's POS keeps no modification time.","format":"date-time","type":"string"},"number":{"description":"The store's running delivery number.","type":"string"},"purchaseOrderId":{"description":"The purchase order this document received (GET /v1/purchase-orders/{posPurchaseOrderId}); absent when it was entered without one. What the purchaseOrderId filter matches.","type":"string"},"purchaseOrderNumber":{"description":"That purchase order's running number; only next to purchaseOrderId.","type":"string"},"quick":{"description":"A quick delivery: entered as a header with a total and no lines.","type":"boolean"},"receivingId":{"description":"The POS receiving id; pass it to GET /v1/receiving/{posReceivingId}.","type":"string"},"source":{"description":"Which program or feed entered the document.","type":"string"},"statusCode":{"description":"The POS workflow status number as stored. Its meaning is a per-store list this read does not carry, so it is not named.","type":"integer"},"totals":{"$ref":"#/components/schemas/PosReceivingTotals","description":"The header money columns as stored. Absent only when the store's POS has none of them."},"transactionType":{"description":"The POS transaction type as stored: 0 a bill, 1 a vendor credit. The sign of a vendor credit's totals is not dependable in storage and the API negates nothing; read this field to tell a credit.","type":"integer"},"vendorCode":{"description":"The vendor's short code in the POS vendor list.","type":"string"},"vendorId":{"description":"The POS vendor id; what vendorId filters on.","type":"string"},"vendorInvoiceNumber":{"description":"The vendor's invoice number for the delivery.","type":"string"},"vendorName":{"description":"The vendor's name in the POS vendor list; absent when the vendor row is gone.","type":"string"}},"required":["receivingId"],"type":"object"},"PosReceivingLine":{"additionalProperties":false,"description":"One line of a receiving document, as stored. The POS buys by the case: quantities count CASES (purchase units of unitsPerCase sell units each) and costs are the cost of ONE CASE, exactly as the POS stores them. The API derives nothing: no unit cost, no extended total and no outstanding quantity is computed, no sign is changed and nothing is clamped. Divide a case cost by unitsPerCase yourself if you need a unit cost.","properties":{"amount":{"description":"The line amount as the POS stored it (the POS stores receivedQuantity x caseCost); never recomputed.","type":"number"},"caseCost":{"description":"Cost of ONE CASE after the document's discount, as stored. Not a unit cost.","type":"number"},"caseCostBeforeDiscount":{"description":"Cost of ONE CASE before the discount, as stored. Not a unit cost.","type":"number"},"costFlag":{"description":"The POS cost-flag letter of the line.","type":"string"},"description":{"description":"The item description on the line.","type":"string"},"discountAmount":{"description":"The line's discount amount, as stored.","type":"number"},"lineId":{"description":"The POS line id.","type":"string"},"lineNumber":{"description":"The line's position on the document, as the POS shows it.","type":"string"},"modifiedAt":{"description":"When the POS last modified the line (UTC).","format":"date-time","type":"string"},"newProduct":{"description":"The line created the product in the POS.","type":"boolean"},"noDiscount":{"description":"The line is excluded from the document's discount.","type":"boolean"},"orderedQuantity":{"description":"The purchase-order line's quantity, in CASES, copied when the order was imported into this document: ordered next to received. On a line that did not come from a purchase order it is whatever the POS left there; the header's purchaseOrderId says whether the document had an order at all. The API never computes a difference.","type":"number"},"productCode":{"description":"The store product code.","type":"string"},"receivedQuantity":{"description":"Quantity received, in CASES, signed as stored (a return to the vendor is negative; a stored null reads 0).","type":"number"},"unitsPerCase":{"description":"Sell units in one case, as the POS copied it from the product when the line was written.","type":"number"},"vendorItemCode":{"description":"The vendor's own item code.","type":"string"}},"required":["lineId","receivedQuantity"],"type":"object"},"PosReceivingTotals":{"additionalProperties":false,"description":"Header totals exactly as the POS stores them; nothing is negated, made absolute, clamped or derived (a vendor credit is told by transactionType, not by a sign). A figure whose column the store lacks is absent; a stored null reads 0. What the store has paid is a payment detail and is never part of it.","properties":{"bill":{"description":"The vendor's bill total.","type":"number"},"discount":{"description":"Discount amount of the document.","type":"number"},"gross":{"description":"Gross total of the document.","type":"number"}},"type":"object"},"PosStoreProfile":{"additionalProperties":false,"description":"The store's business profile: the name and contact block its register prints at the top of every receipt, its tax slots and its POS database version. Every text is as the store keeps it and is absent when blank; nothing is derived. It never carries a license value, a payment processor or terminal id, a carrier account, a machine path, a PIN or staff setting, a pricing or discount rule, the receipt footer or custom text, or the enterprise ids.","properties":{"addressLine1":{"description":"Street address.","type":"string"},"addressLine2":{"description":"Second address line.","type":"string"},"city":{"description":"City.","type":"string"},"currency":{"description":"ISO 4217 currency of the store's amounts, where CompuDime configured it on the store's POS agent (the POS itself keeps none); absent otherwise.","type":"string"},"databaseVersion":{"description":"The TisWin3 database version of the store's POS (for example 1.324). Several reads depend on it: the POS keeps the category and brand lists from 1.308 (an older store's lists are built from its products), an invoice's externalId and processorCode exist from 1.324. Absent when the store's POS does not say.","pattern":"^[0-9]+\\.[0-9]+$","type":"string"},"email":{"description":"The store's public email address, as printed on its receipts.","type":"string"},"fax":{"description":"The store's fax, as the store wrote it.","type":"string"},"name":{"description":"The store's name as its POS is licensed to it, which TisWin3 shows and the register prints at the top of the receipt.","type":"string"},"nameLine2":{"description":"The line the receipt prints under the name, often a legal or trading name.","type":"string"},"phone":{"description":"The store's phone, as the store wrote it (formatting kept).","type":"string"},"postalCode":{"description":"ZIP code, as the store keeps it.","type":"string"},"state":{"description":"State, as the store keeps it (two letters in the POS).","type":"string"},"taxRates":{"description":"The register's two tax slots, in slot order; a slot is listed when the store's POS keeps any of its settings.","items":{"$ref":"#/components/schemas/PosStoreTaxRate"},"maxItems":2,"type":"array"},"timeZone":{"description":"IANA time zone of the store, where CompuDime configured it on the store's POS agent; absent otherwise.","type":"string"},"utcOffset":{"description":"The store clock's offset from UTC when the profile was read (for example -04:00): the zone every store-local date and time of this API is read in.","pattern":"^[+-][0-9]{2}:[0-9]{2}$","type":"string"},"website":{"description":"The store's website, as printed on its receipts.","type":"string"}},"type":"object"},"PosStoreTaxRate":{"additionalProperties":false,"description":"One register tax slot, as the store keeps it.","properties":{"exemptBelowUnitPrice":{"description":"The register charges the slot's tax on a taxable line only when the line's unit price is at least this amount; 0 means every taxable line is taxed. Absent when the store keeps no such setting.","type":"number"},"label":{"description":"The caption the receipt prints for the slot's tax. Absent when blank; the register then prints TAX (slot 1) or TAX 2 (slot 2).","type":"string"},"ratePercent":{"description":"The slot's rate in percent as stored (8.625 means 8.625 %). 0 means the slot charges nothing.","type":"number"},"slot":{"description":"The slot every POS tax figure refers to: an invoice's taxRate1 / taxRate2 and a line's taxable1 / taxable2.","enum":[1,2],"type":"integer"}},"required":["slot"],"type":"object"},"PosTag":{"additionalProperties":false,"description":"One tag the store's products carry. Each row is a value the store's products carry, exactly as they carry it in the matching product field (brand, department, category, subCategory, or one of a product's tags), with the number of products carrying it (inactive products included). The POS keeps these lists itself from the product file and removes a value when no product carries it any more; modifiedSince cannot report a removal, so re-read the whole list now and then to drop the values that are gone. The POS keeps them from TisWin3 database version 1.308 (GET /v1/store says the store's version). Where a store's POS keeps no such list, or keeps it empty, the list is built from the products themselves at the moment of the call: the same rows in the same shape, each count taken then, and as modifiedAt the newest change of any product carrying the value.","properties":{"modifiedAt":{"description":"When the POS last changed the row (UTC); what modifiedSince filters on. It changes with every product that gains or loses the value. On a list built from the products it is the newest change of any product carrying the value, so it also moves when such a product changes for another reason. Absent when the store's list keeps no modification time.","format":"date-time","type":"string"},"name":{"description":"The tag exactly as the products carry it (a product's tags are separated by spaces in the POS, so a tag has none).","type":"string"},"productCount":{"description":"The number of products carrying the value (inactive products included): the POS's own count as it keeps it, or, on a list built from the products, the count at the moment of the call. Absent when the store's list keeps no count.","type":"integer"}},"required":["name"],"type":"object"},"PosTicket":{"additionalProperties":false,"description":"One register ticket, as the POS stored it. A field whose column the store's POS lacks, or that the POS left blank, is absent. A ticket never says who rang it or who the customer is beyond the POS customer id: no cashier, no remark, no phone. A tender never carries a card number, its last four digits, an authorization or reference code, a check number, a gift-card number, an EBT or gift-card balance or a signature: the store agent never reads the columns that hold them.","properties":{"anonymousCustomer":{"description":"Present and true when the ticket belongs to the register's anonymous walk-in or remote-customer placeholder account, which is not a customer; absent otherwise.","type":"boolean"},"businessDay":{"description":"The business day the POS assigned the ticket, else its date (YYYY-MM-DD).","format":"date","type":"string"},"createdAt":{"description":"date and time as one instant (UTC).","format":"date-time","type":"string"},"customerDiscountPercent":{"description":"The customer's ticket discount percentage.","type":"number"},"customerId":{"description":"The POS customer id (posCustomerId on the customer reads) of the account the ticket names, when exactly one account carries it. Absent, with anonymousCustomer true, on a ticket of the register's walk-in or remote-customer placeholder account; absent too when the ticket names no account or one the store cannot tell apart.","type":"string"},"date":{"description":"The day the ticket was started (the store's calendar).","format":"date","type":"string"},"finishedAt":{"description":"When the register last finished the ticket: completed, held or voided (UTC). Later edits on the ticket screens do not move it.","format":"date-time","type":"string"},"lines":{"description":"Single-ticket read only: every line row of the ticket in the register's receipt order, voided lines included (voided true). Lines of tickets the store moved to its line archive are not read, so such a ticket has no lines.","items":{"$ref":"#/components/schemas/PosTicketLine"},"maxItems":500,"type":"array"},"linesTruncated":{"description":"Single-ticket read only: the ticket has more than the 500 lines one answer carries.","type":"boolean"},"logNumber":{"description":"The register log (shift) the ticket was rung in: logNumber on a Z-report log.","type":"integer"},"paperBagCount":{"description":"Paper bags charged.","type":"number"},"payType":{"description":"The tender code of the only tender, M when there were several (the ticket's pay type as the register wrote it).","type":"string"},"priceLevel":{"description":"The ticket's price level, at stores that use level pricing.","type":"integer"},"register":{"description":"The register code the ticket id starts with (01, 32, or one character on older databases).","type":"string"},"sale":{"description":"True for the sale types S and O only; count only these as revenue.","type":"boolean"},"taxExempt":{"description":"The ticket was rung tax exempt.","type":"boolean"},"taxRate1":{"description":"The first tax rate in percent, as the ticket captured it.","type":"number"},"taxRate2":{"description":"The second tax rate in percent.","type":"number"},"tenders":{"description":"Single-ticket read only: every tender row of the ticket, in the order it was taken. The change given is not a tender row; it is totals.change.","items":{"$ref":"#/components/schemas/PosTicketTender"},"maxItems":100,"type":"array"},"tendersTruncated":{"description":"Single-ticket read only: the ticket has more than the 100 tenders one answer carries.","type":"boolean"},"ticketDiscountPercent":{"description":"The cashier's ticket discount percentage (only one of the two discount percentages is ever set).","type":"number"},"ticketId":{"description":"The POS ticket id: the register code, the date and the time the ticket was started. Pass it to GET /v1/tickets/{ticketId}. The register moves the seconds forward to keep ids unique, so read dates and times from date, time and createdAt, not from the id.","type":"string"},"time":{"description":"The time the ticket was started, the store's wall clock (HH:MM:SS).","type":"string"},"totals":{"$ref":"#/components/schemas/PosTicketTotals"},"type":{"description":"The ticket type as the register wrote it. Only the two sale types are read unless type names others: S (a completed register sale) and O (a direct account charge or payment, which normally carries a sale of 0). The other types are not sales and must never be summed as revenue: V a voided sale (its sale total is still filled in), T calculate-only or a transfer whose value already landed on another ticket (it would double-count), R a transfer ticket not yet paid, G training mode, H a held sale and A a sale still being rung. Compare with type and sale on a row.","enum":["S","O","V","T","R","G","H","A"],"type":"string"},"upChargePercent":{"description":"The up-charge percentage on the ticket.","type":"number"}},"required":["ticketId","type","sale"],"type":"object"},"PosTicketLine":{"additionalProperties":false,"description":"One line row of a register ticket, as stored. extendedAmount, lineTotal and tax are the register's own figures; lineTotal and tax are computed when a sale finishes and are 0 on every ticket that is not an S ticket.","properties":{"aliasCode":{"description":"The alias code the item was scanned by.","type":"string"},"bogoPrice":{"description":"The buy-one-get-one unit price. Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"casePrice":{"description":"The case price. Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"caseSalePrice":{"description":"The sale case price. Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"cases":{"description":"Sold by the case (a flag, not a count).","type":"boolean"},"category":{"description":"The item's category.","type":"string"},"department":{"description":"The item's department.","type":"string"},"description":{"description":"The item description on the receipt.","type":"string"},"discountPercent":{"description":"The line's percentage discount.","type":"number"},"discounted":{"description":"The line got a discount.","type":"boolean"},"extendedAmount":{"description":"The extension after the item's best price, before the ticket discount and deposits (unsigned, as stored).","type":"number"},"foodStamp":{"description":"Food-stamp eligible.","type":"boolean"},"kind":{"description":"What the line is, from the key the cashier pressed: sale (an item sold), minus (a negative item line), return (a return), discount (a DISCOUNT % or DISCOUNT ON marker row with no quantity), other (legacy payment, change and paid-out rows).","enum":["sale","minus","return","discount","other"],"type":"string"},"lineId":{"description":"The POS line id.","type":"string"},"lineNumber":{"description":"The order the line was rung in.","type":"integer"},"lineTotal":{"description":"The line's sold total: signed, after the ticket discount, with deposit and up-charge, tax excluded.","type":"number"},"longDescription":{"description":"The item's long description, at stores that keep one on the line.","type":"string"},"mixMatch":{"description":"The mix-and-match group the line was priced in.","type":"string"},"noDiscount":{"description":"The item is excluded from the ticket discount.","type":"boolean"},"overLimitQuantity":{"description":"The part of quantity above the item's sale limit, charged at the regular price.","type":"number"},"packagePrice":{"description":"The package price (packageQuantity for packagePrice). Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"packageQuantity":{"description":"How many units the package price is for.","type":"number"},"packageSalePrice":{"description":"The sale package price (packageSaleQuantity for packageSalePrice). Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"packageSaleQuantity":{"description":"How many units the sale package price is for.","type":"number"},"price":{"description":"The item's regular unit price. Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"priceLevel":{"description":"How the register priced the line: 1 regular, 2 sale, 3, 4, 13 and 16 package and sale-package prices, 5 to 11 case prices, 12 a percent discount, 14 mix and match, 15 buy one get one.","type":"integer"},"productCode":{"description":"The store product code.","type":"string"},"quantity":{"description":"The quantity rung: cases on a case line, pounds on a scale line (the register's count plus its over-limit count). Positive on a return line; see soldUnits for the sign.","type":"number"},"salePrice":{"description":"The unit price after a sale or an item discount (equal to price when there was none). Dollars (the POS stores it in cents and the API divides by 100, as TisWin3 shows it). Absent on a discount marker or other row.","type":"number"},"scale":{"description":"An item sold by weight.","type":"boolean"},"soldUnits":{"description":"Signed units sold (negative on a return), cases times the pack; 0 on every ticket that is not an S ticket.","type":"number"},"tax":{"description":"The line's share of the ticket tax.","type":"number"},"taxable1":{"description":"The first tax applies to the line.","type":"boolean"},"taxable2":{"description":"The second tax applies to the line.","type":"boolean"},"unitsPerCase":{"description":"Units in a case of the item.","type":"number"},"voided":{"description":"Present and true when the item line was voided on the register (its quantity is 0); a voided line stays on the ticket.","type":"boolean"},"wic":{"description":"WIC eligible.","type":"boolean"}},"required":["kind","quantity"],"type":"object"},"PosTicketTender":{"additionalProperties":false,"description":"One tender row of a register ticket. Only the tender type, the amount, the date, the register log and the row id are read. A ticket never says who rang it or who the customer is beyond the POS customer id: no cashier, no remark, no phone. A tender never carries a card number, its last four digits, an authorization or reference code, a check number, a gift-card number, an EBT or gift-card balance or a signature: the store agent never reads the columns that hold them.","properties":{"action":{"description":"What the row records: payment, void (a voided payment, negative), credit (a refund on a return, negative), void_credit, activate (a gift card activated, negative), add_value (value added to a gift card, negative), void_add_value, auth_only (a card authorization only).","enum":["payment","void","credit","void_credit","activate","add_value","void_add_value","auth_only","other"],"type":"string"},"amount":{"description":"The amount, signed exactly as the POS stores it; a cash row holds the full amount tendered.","type":"number"},"date":{"description":"The payment date.","format":"date","type":"string"},"lineId":{"description":"The POS row id of the tender.","type":"string"},"logNumber":{"description":"The register log at payment time.","type":"integer"},"tenderCode":{"description":"The tender code (tenders.list code); 1 to 8 on legacy rows.","type":"string"},"tenderName":{"description":"The tender's name in the store's tender list.","type":"string"}},"required":["action","amount"],"type":"object"},"PosTicketTotals":{"additionalProperties":false,"description":"The ticket's money columns in dollars, signed exactly as the POS stores them; nothing is clamped or derived. A figure whose column the store lacks, or that the POS left blank, is absent.","properties":{"change":{"description":"Change given.","type":"number"},"codCharge":{"description":"The COD part of onAccount.","type":"number"},"discount":{"description":"The ticket percentage discount amount only; item discounts are on the lines.","type":"number"},"onAccount":{"description":"Charged to the customer's account (COD included).","type":"number"},"paid":{"description":"Every tender taken, over-tender included: the change is change, not subtracted here.","type":"number"},"paidOnAccount":{"description":"A payment toward the customer's account balance taken on the ticket.","type":"number"},"paperBagFee":{"description":"The paper-bag fee, included in sale.","type":"number"},"returns":{"description":"Returns on the ticket, a positive amount (return tax and deposits included).","type":"number"},"sale":{"description":"The receipt total: tax included, returns and the ticket discount taken off, deposits, the paper-bag fee and the up-charge included. Negative on a return-only ticket. It is filled in on voided and held tickets too, which is why only the sale types count.","type":"number"},"tax":{"description":"Tax (both taxes), net of returns.","type":"number"},"upCharge":{"description":"The up-charge amount, included in sale.","type":"number"}},"type":"object"},"PosZReportDrawer":{"additionalProperties":false,"description":"The three amounts the cashier enters for the whole log. The register's printed over/short compares countedCash with the starting cash plus the drawer tenders, less change, paid-outs and leftInDrawer; the API does not compute it. Absent when the store keeps none of them.","properties":{"countedCash":{"description":"The total the cashier counted in the register at close.","type":"number"},"leftInDrawer":{"description":"The amount left in the drawer at close.","type":"number"},"startingCash":{"description":"Cash in the drawer when the log was opened.","type":"number"}},"type":"object"},"PosZReportLog":{"additionalProperties":false,"description":"One register log (a register's shift; the register prints its Z tape when the log is closed), with the totals the register keeps for it. Every figure is the register's own running total, as stored: an open log changes with every sale, and a closed log can still change when a ticket is edited or the log is recalculated. The cashier names and the cost-derived margins on the log are never part of it.","properties":{"businessDay":{"description":"The business day the log belongs to.","format":"date","type":"string"},"closed":{"description":"The log was closed (its Z was taken). An open log's totals are an X reading and still change.","type":"boolean"},"drawer":{"$ref":"#/components/schemas/PosZReportDrawer"},"endedAt":{"description":"When the log was closed (UTC). The register may record the time of the last sale instead of the close.","format":"date-time","type":"string"},"lastTransactionAt":{"description":"When the last transaction was posted to the log (UTC).","format":"date-time","type":"string"},"logNumber":{"description":"The register log number: logNumber on a ticket rung in it.","type":"integer"},"register":{"description":"The register code.","type":"string"},"startedAt":{"description":"When the log was opened (UTC).","format":"date-time","type":"string"},"tenders":{"description":"The log's totals per tender and source, as the register computed them (the register keeps no counted amount per tender). Empty for a log without any (logs of register builds older than 8.8.2 keep none).","items":{"$ref":"#/components/schemas/PosZReportTender"},"type":"array"},"totals":{"$ref":"#/components/schemas/PosZReportTotals"}},"required":["register","logNumber","businessDay","closed","totals","tenders"],"type":"object"},"PosZReportTender":{"additionalProperties":false,"description":"One tender total of a register log.","properties":{"amount":{"description":"The register's computed total for the tender and source.","type":"number"},"count":{"description":"How many tender rows made the total.","type":"number"},"source":{"description":"sales (payments on tickets), paid_outs (paid-outs from the drawer) or account (payments taken on the account screen); another letter the register writes is passed through lower-cased.","type":"string"},"tenderCode":{"description":"The tender code (tenders.list code).","type":"string"},"tenderName":{"description":"The tender's name in the store's tender list.","type":"string"}},"required":["source","tenderCode","amount"],"type":"object"},"PosZReportTotals":{"additionalProperties":false,"description":"The log's totals in dollars (counts where noted), exactly as the register stores them. A figure whose column the store lacks, or that the POS left blank, is absent.","properties":{"billedToAccount":{"description":"Amounts billed to customer accounts.","type":"number"},"calculateOnly":{"description":"Calculate-only sales (not sales).","type":"number"},"change":{"description":"Change given.","type":"number"},"codCharges":{"description":"COD charges.","type":"number"},"discounts":{"description":"All discounts.","type":"number"},"drawerOpens":{"description":"Manual drawer opens (a count).","type":"number"},"itemDiscounts":{"description":"Item discounts.","type":"number"},"minusLines":{"description":"Minus item lines.","type":"number"},"moneyTaken":{"description":"Every tender taken, less change and paid-outs, plus the starting cash (the register's REGMONY).","type":"number"},"nonTaxable1":{"description":"Non-taxable sales for the first tax, as the register works it out.","type":"number"},"nonTaxable2":{"description":"Non-taxable sales for the second tax.","type":"number"},"paidOnAccount":{"description":"Payments toward customer accounts.","type":"number"},"paidOuts":{"description":"Paid-outs from the drawer.","type":"number"},"returns":{"description":"Returns.","type":"number"},"tax":{"description":"All tax.","type":"number"},"tax2":{"description":"The second tax's part of tax (the Z prints tax 1 as tax - tax2).","type":"number"},"taxExempt1":{"description":"Taxable items sold on tax-exempt tickets, first tax.","type":"number"},"taxExempt2":{"description":"Taxable items sold on tax-exempt tickets, second tax.","type":"number"},"taxable1":{"description":"Taxable sales for the first tax (after discounts, less the food-stamp-paid part).","type":"number"},"taxable2":{"description":"Taxable sales for the second tax.","type":"number"},"ticketDiscounts":{"description":"Ticket (customer and cashier percentage) discounts.","type":"number"},"transactions":{"description":"Sales posted to the log (a count).","type":"number"},"voidedSales":{"description":"Whole sales voided.","type":"number"}},"type":"object"},"Problem":{"additionalProperties":false,"properties":{"code":{"type":"string"},"detail":{"type":"string"},"docsUrl":{"description":"Where this problem code is documented, on the address you call the API on: \u003cAPI address\u003e/docs/errors#\u003ccode\u003e. Present when the deployment knows its address.","format":"uri","type":"string"},"integrationId":{"description":"The integration the API key belongs to. Present once the key has been authenticated: on every problem except a 401 and a 404 or 405 answered before authentication. Quote it with requestId when asking CompuDime for support.","type":"string"},"requestId":{"type":"string"},"retryable":{"type":"boolean"},"status":{"type":"integer"},"statusUrl":{"description":"The public status page (no key needed): check it before retrying a 5xx. A deployment without a status page names its own readiness report, \u003cpublic base URL\u003e/readyz. Present when the deployment knows either.","format":"uri","type":"string"},"storeId":{"description":"The store the API key belongs to. Present exactly when integrationId is; never on a 401.","type":"string"},"support":{"description":"Where to ask CompuDime for help, as a mailto: URI: mailto:\u003csupport address\u003e. Write there with requestId, and integrationId when the problem has one; never send a key. Present when the deployment has a support address.","format":"uri","type":"string"},"title":{"type":"string"},"type":{"description":"A stable identifier of the problem: https://api.compudime.com/docs/errors#\u003ccode\u003e, the same on every deployment. Compare it as a string; it is also the code's entry on the errors page, so following it explains the problem.","format":"uri","type":"string"}},"required":["type","title","status","code","detail","requestId","retryable"],"type":"object"},"Product":{"additionalProperties":false,"properties":{"active":{"description":"false when the store marks the item not for sale (PrdMstr.NoSale): the register refuses to ring it. It does not reflect the product file's inactive flag, which is inactive.","type":"boolean"},"brand":{"type":"string"},"category":{"type":"string"},"department":{"type":"string"},"description":{"type":"string"},"inactive":{"description":"Flagged inactive in the product file (PrdMstr.InActive): the store's back office hides it from its lists, but the register still sells it. null until the store's agent reports the flag. GET /v1/products leaves out the products where it is true unless the call passes includeInactive=true.","type":["boolean","null"]},"lastModifiedUtc":{"description":"When the product's row in the store's product file last changed (PrdMstr.UpdatedOn, which the store's database stamps on every write to the row, in the store's time zone, reported here in UTC). Any write moves it, including the register's daily last-sold stamp and receiving updates to columns this API does not return, so modifiedSince also returns products whose visible fields did not change. Like lastSold it is refreshed at least once a day, and with every snapshot that carries another change. Empty (\"\") until the store's agent reports it.","type":"string"},"lastSold":{"description":"The day the register last finished a sale with this item on it (PrdMstr.LastSold, a date without a time, the store's calendar day). Register sales only: the register stamps it on each item of a completed sale ticket with a nonzero quantity on its line, so a voided line, a voided, held or training ticket, an account charge and an order or delivery invoice never stamp it; a return rung on a sale ticket does. null when the item has never been stamped (or the store turned the stamp off) and until the store's agent reports it. On the snapshot it is refreshed at least once a day, not every hour: a change to lastSold alone reaches the snapshot with the store's first snapshot of the next day. Use the live lookup for today's value.","format":"date","type":["string","null"]},"pack":{"type":"string"},"price":{"type":"string"},"priceQty":{"type":"integer"},"productCode":{"description":"The product's code at the store: the code the register scans and sells by (for most items the barcode).","type":"string"},"size":{"type":"string"},"smallDescription":{"type":"string"},"taxable":{"type":"boolean"},"unitsPerCase":{"description":"Units per case (PrdMstr.UPC). Not a barcode.","type":"string"},"upc":{"deprecated":true,"description":"Deprecated: use unitsPerCase, which carries the same value. upc keeps working and is not removed before a later, announced date. Units per case, as the POS stores it (its column is named UPC). This is NOT a barcode; the scannable code is productCode.","type":"string"}},"type":"object"},"ProductListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"fieldPolicyId":{"type":"string"},"fieldPolicyVersion":{"type":"integer"},"nextCursor":{"type":"string"},"products":{"items":{"$ref":"#/components/schemas/Product"},"type":"array"},"requestedFieldCount":{"type":"integer"}},"type":"object"},"ProductLookupResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the row from the POS.","format":"date-time","type":"string"},"product":{"$ref":"#/components/schemas/LiveProduct"},"requestId":{"type":"string"},"source":{"description":"Always live: the row was read from the store at request time, not from the hourly snapshot.","enum":["live"],"type":"string"}},"required":["requestId","product","generatedAt","source"],"type":"object"},"Promotion":{"additionalProperties":false,"description":"One promotion the store's register may apply. A field the promotion does not have is absent. Money is as the POS stores it; a percent deal is never converted to a price. runningNow is the register's own answer at the moment in evaluatedAt (the store database's clock): the store's TIS01 register window rules, applied by the store agent exactly as the register applies them. The dates hold (an empty date always holds); beginTime counts only on the begin date (and not at all without a begin date); endTime counts only on the end date, or on every day when there is no end date; days, when listed, must include the weekday. A scheduled price has no days. A package deal has no window. A mix and match membership is running when one of the product's qualifying deals would pool it in its group now. A promotion a store-written rule decides (the product's own rule, the store's discount rule, a scheduled price's condition or rule) says storeRuleDecides and status storeRule, carries no runningNow, and is never evaluated by the API; status undetermined (with undeterminedReason) marks store data the API cannot evaluate exactly, such as a time of day that is not four digits. runningNow does not weigh one promotion against another: the register charges the best of the deals that apply, a running scheduled price replaces the product's own price it sets, and on a ticket where discounts are off (see discountsOnByDefault) the register gives none of them.","properties":{"brand":{"description":"The product's brand; on a brand scheduled price, the brand it covers.","type":"string"},"category":{"description":"The product's category; on a category scheduled price, the category it covers.","type":"string"},"department":{"description":"The product's department.","type":"string"},"description":{"description":"The product's description.","type":"string"},"maxQuantity":{"description":"Only this many get the deal; the rest pay the next price (units, or cases for a case sale).","type":"integer"},"maxQuantityPer":{"description":"What maxQuantity counts, on a product's own deal: line (one ticket line), customerDay (the customer's discounted units today, earlier tickets included) or customerPromotion (since the promotion began). A per-customer limit needs a customer on the ticket.","enum":["line","customerDay","customerPromotion"],"type":"string"},"minQuantity":{"description":"The line's count must reach this for the deal to apply (a sale and a package sale count units, a case sale counts cases).","type":"integer"},"mixMatch":{"$ref":"#/components/schemas/PromotionMixMatch"},"mode":{"description":"amount: price is the deal price. percent: percentOff is taken off the regular price (a sale), the package price or the regular price times quantity (a package sale), or the case price (a case sale); the register rounds to whole cents.","enum":["amount","percent"],"type":"string"},"percentOff":{"description":"Percent off, in percent (15 is 15 %).","type":"number"},"permanentChange":{"description":"scheduledPrice only: once it starts, the price becomes the product's own price (a scheduled price change) instead of running for a period.","type":"boolean"},"price":{"description":"The deal price for quantity units (one unit when quantity is absent; a case sale's price is per case).","type":"number"},"priceField":{"description":"scheduledPrice only: which price it sets while it runs.","enum":["price","sale","casePrice","caseSale","packagePrice","packageSale"],"type":"string"},"productCode":{"description":"The POS product code; absent on a category or brand scheduled price.","type":"string"},"promotionId":{"description":"Stable id: \u003ctype\u003e:\u003cproductCode\u003e for a deal kept on the product, scheduledPrice:\u003crow id\u003e for a scheduled price.","type":"string"},"quantity":{"description":"Units the price buys: the package size, or the units in a case.","type":"integer"},"regularPrice":{"description":"The product's own regular unit price.","type":"number"},"runningNow":{"description":"Whether the register applies it at evaluatedAt. Absent when a store rule decides or the data cannot be evaluated exactly.","type":"boolean"},"scope":{"description":"scheduledPrice only: whom the price covers. The register uses a product's own scheduled prices first, then its category's, then its brand's (brand only where the store's registers keep brands on tickets); among rows of one price field the lowest price per unit wins.","enum":["product","category","brand"],"type":"string"},"status":{"description":"At evaluatedAt: running (applied now), notNow (within its dates, but its time of day or weekdays exclude this moment; a mix and match membership whose qualifying deals are not on), upcoming (begins after today), ended (will never apply again; only an activeOn read of a past day returns one), storeRule (a store-written rule decides; not evaluated), undetermined (the store's data cannot be evaluated exactly; see undeterminedReason).","enum":["running","notNow","upcoming","ended","storeRule","undetermined"],"type":"string"},"storeRule":{"description":"The name of that rule, when it has one (a scheduled price's condition has none).","type":"string"},"storeRuleDecides":{"description":"Present and true when a store-written rule decides whether the register applies it; the API never evaluates such a rule.","type":"boolean"},"type":{"description":"sale (a unit sale price), package (the standing N for a price deal, no window), packageSale (a package sale), caseSale (a case sale), mixMatch (the product's membership of a mix and match group) or scheduledPrice (a price the store scheduled for a product, a category or a brand).","enum":["sale","package","packageSale","caseSale","mixMatch","scheduledPrice"],"type":"string"},"undeterminedReason":{"description":"Why the promotion could not be evaluated exactly (status undetermined).","type":"string"},"unitsPerCase":{"description":"Units in one case (the POS column PrdMstr.UPC, which is not a barcode).","type":"integer"},"window":{"$ref":"#/components/schemas/PromotionWindow"}},"required":["promotionId","type","status"],"type":"object"},"PromotionClock":{"additionalProperties":false,"description":"The store moment the promotions were evaluated at (the store database's clock).","properties":{"date":{"format":"date","type":"string"},"time":{"description":"HH:MM, store wall clock.","type":"string"},"weekday":{"enum":["sunday","monday","tuesday","wednesday","thursday","friday","saturday"],"type":"string"}},"required":["date","time","weekday"],"type":"object"},"PromotionListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"discountsOnByDefault":{"description":"The store's registers give deal prices on every ticket unless a cashier turns discounts off (true), or only on tickets where a cashier turns them on (false). Absent when the store's registers are not all set the same way.","type":"boolean"},"evaluatedAt":{"$ref":"#/components/schemas/PromotionClock"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"promotions":{"description":"One page: first the deals kept on products (by product code, then sale, package, package sale, case sale, mix and match), then the scheduled prices (by scope, code, price field). Inactive and not-for-sale products are never listed.","items":{"$ref":"#/components/schemas/Promotion"},"maxItems":200,"type":"array"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","promotions","nextCursor","evaluatedAt","generatedAt","source"],"type":"object"},"PromotionMixMatch":{"additionalProperties":false,"description":"A product's membership of a mix and match group: members pool their counts, and the pooled count is priced with the deal of the first member rung up. Read the whole group with GET /v1/promotions/mix-match/{groupId}.","properties":{"bogo":{"description":"The group's BOGO settings, as data, when the product is a BOGO member.","items":{"$ref":"#/components/schemas/MixMatchBogo"},"type":"array"},"bogoMember":{"description":"The member takes part in the group's BOGO.","type":"boolean"},"groupDescription":{"description":"The group's description.","type":"string"},"groupId":{"description":"The group id.","type":"string"},"pooled":{"description":"The member's count is pooled with the group's other members when one of its qualifying deals is on.","type":"boolean"},"qualifyingDeals":{"description":"The member's deals that pool it: sale (a sale with a minimum or a maximum), package, packageSale (a package sale, or a package), caseSale (a case sale with a minimum or a maximum).","items":{"enum":["sale","package","packageSale","caseSale"],"type":"string"},"type":"array"}},"required":["groupId","pooled","qualifyingDeals"],"type":"object"},"PromotionWindow":{"additionalProperties":false,"description":"The deal's window as the store keeps it. beginTime counts only on the begin date (and not at all without one); endTime counts only on the end date, or on every day when there is no end date. Absent when the deal has no window.","properties":{"beginTime":{"description":"Store wall clock HH:MM; a stored value that is not four digits is passed as stored.","type":"string"},"begins":{"description":"First day (YYYY-MM-DD, the store's calendar).","format":"date","type":"string"},"days":{"description":"The weekdays it runs on; every day when absent.","items":{"enum":["sunday","monday","tuesday","wednesday","thursday","friday","saturday"],"type":"string"},"type":"array"},"endTime":{"description":"Store wall clock HH:MM, inclusive; a stored value that is not four digits is passed as stored.","type":"string"},"expires":{"description":"Last day (YYYY-MM-DD, inclusive).","format":"date","type":"string"}},"type":"object"},"PurchaseOrderListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"purchaseOrders":{"description":"One page of purchase-order headers in a stable order (purchase order id, then vendor id). A list row never carries lines or linesTruncated; read the order for those.","items":{"$ref":"#/components/schemas/PosPurchaseOrder"},"maxItems":200,"type":"array"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","purchaseOrders","nextCursor","generatedAt","source"],"type":"object"},"PurchaseOrderResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"purchaseOrder":{"$ref":"#/components/schemas/PosPurchaseOrder"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","purchaseOrder","generatedAt","source"],"type":"object"},"ReasonListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"reasons":{"description":"The discount reasons, then the return reasons. Not paged: one answer carries every reason, up to 500.","items":{"$ref":"#/components/schemas/PosReason"},"maxItems":500,"type":"array"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"truncated":{"description":"True when the store has more than 500 reasons and the rest were left out.","type":"boolean"}},"required":["requestId","reasons","truncated","generatedAt","source"],"type":"object"},"ReceivingListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"receivings":{"description":"One page of receiving-document headers in a stable order (receiving id, then vendor id). A list row never carries lines or linesTruncated; read the document for those.","items":{"$ref":"#/components/schemas/PosReceiving"},"maxItems":200,"type":"array"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","receivings","nextCursor","generatedAt","source"],"type":"object"},"ReceivingResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"receiving":{"$ref":"#/components/schemas/PosReceiving"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"}},"required":["requestId","receiving","generatedAt","source"],"type":"object"},"SalesDailyResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"coveredFrom":{"description":"Earliest business day the sync has imported; null when never synced.","format":"date","type":["string","null"]},"coveredTo":{"description":"Latest business day the sync has imported; null when never synced.","format":"date","type":["string","null"]},"fromBusinessDay":{"format":"date","type":"string"},"generatedAt":{"description":"When the POS generated the last sales snapshot; null when the store has never synced.","format":"date-time","type":["string","null"]},"lastSuccessAt":{"description":"When the sales sync last succeeded for this store; null when the store has never synced.","format":"date-time","type":["string","null"]},"requestId":{"type":"string"},"rows":{"description":"One row per business day in [from,to] that has data, ordered by businessDay ascending; days with no register activity are absent.","items":{"$ref":"#/components/schemas/SalesDailyRow"},"type":"array"},"toBusinessDay":{"format":"date","type":"string"}},"required":["requestId","fromBusinessDay","toBusinessDay","generatedAt","lastSuccessAt","coveredFrom","coveredTo","rows"],"type":"object"},"SalesDailyRow":{"additionalProperties":false,"description":"One business day's register totals for the store. Money is decimal dollars rounded to 2 places (never cents).","properties":{"businessDay":{"description":"Register business day (YYYY-MM-DD).","format":"date","type":"string"},"discounts":{"description":"Discounts in dollars.","type":"number"},"netSales":{"description":"Net sales in dollars (net of returns).","type":"number"},"onAccount":{"description":"On-account (charge) sales in dollars.","type":"number"},"returns":{"description":"Returns in dollars.","type":"number"},"tax":{"description":"Tax collected in dollars.","type":"number"},"tickets":{"description":"Sales tickets closed on the day.","type":"integer"},"voidsAmt":{"description":"Voided amount in dollars.","type":"number"},"voidsCnt":{"description":"Voided lines on the day.","type":"integer"}},"required":["businessDay","tickets","netSales","returns","discounts","tax","onAccount","voidsCnt","voidsAmt"],"type":"object"},"SalesMovementResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"coveredFrom":{"format":"date","type":"string"},"coveredTo":{"format":"date","type":"string"},"fieldPolicyVersion":{"type":"integer"},"generatedAt":{"format":"date-time","type":"string"},"lastSuccessAt":{"format":"date-time","type":"string"},"nextCursor":{"type":"string"},"rows":{"items":{"$ref":"#/components/schemas/SalesMovementRow"},"type":"array"},"type":{"enum":["register","delivery"],"type":"string"}},"type":"object"},"SalesMovementRow":{"additionalProperties":true,"description":"One product's movement for one business day. Only the fields allowed by the key's pinned policy are present.","properties":{"brand":{"type":"string"},"businessDay":{"format":"date","type":"string"},"category":{"type":"string"},"department":{"type":"string"},"description":{"type":"string"},"lines":{"type":"integer"},"productCode":{"type":"string"},"qty":{"type":"number"},"salesAmount":{"type":"number"},"weight":{"type":"number"}},"type":"object"},"StoreProfileResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"store":{"$ref":"#/components/schemas/PosStoreProfile"}},"required":["requestId","store","generatedAt","source"],"type":"object"},"TagListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"tags":{"description":"One page of product tags in a stable order that is not alphabetical (the POS's row id, or on a list built from the products a hash of the value); sort by name yourself for display. Customer tags are never listed.","items":{"$ref":"#/components/schemas/PosTag"},"maxItems":500,"type":"array"}},"required":["requestId","tags","nextCursor","generatedAt","source"],"type":"object"},"TenderListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"requestId":{"type":"string"},"tenders":{"items":{"additionalProperties":false,"properties":{"code":{"type":"string"},"group":{"type":"string"},"name":{"type":"string"},"position":{"type":"integer"}},"required":["code","name"],"type":"object"},"type":"array"}},"required":["requestId","tenders"],"type":"object"},"TicketListResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"nextCursor":{"description":"Pass as cursor to read the next page; empty on the last page.","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"tickets":{"description":"One page of ticket headers in a stable order (ticket id, then type). A list row never carries lines or tenders; read the ticket for those.","items":{"$ref":"#/components/schemas/PosTicket"},"maxItems":200,"type":"array"}},"required":["requestId","tickets","nextCursor","generatedAt","source"],"type":"object"},"TicketResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"ticket":{"$ref":"#/components/schemas/PosTicket"}},"required":["requestId","ticket","generatedAt","source"],"type":"object"},"UsageSummary":{"additionalProperties":false,"properties":{"baseCredits":{"type":"integer"},"billingMode":{"type":"string"},"cardRequired":{"type":"boolean"},"cardState":{"type":"string"},"currentPeriod":{"type":"string"},"endpoints":{"items":{"additionalProperties":false,"properties":{"baseCredits":{"type":"integer"},"endpointId":{"type":"string"},"extraFieldCredits":{"type":"integer"},"requests":{"type":"integer"},"totalCredits":{"type":"integer"}},"type":"object"},"type":"array"},"extraFieldCredits":{"type":"integer"},"houseRequests":{"type":"integer"},"includedCredits":{"type":"integer"},"meter":{"type":"string"},"meters":{"items":{"$ref":"#/components/schemas/UsageSummary"},"type":"array"},"overageCapCredits":{"type":"integer"},"overageCredits":{"type":"integer"},"overageEnabled":{"type":"boolean"},"pendingCredits":{"type":"integer"},"planId":{"type":"string"},"pricingVersion":{"type":"string"},"sandboxIncludedCredits":{"type":"integer"},"sandboxUsedCredits":{"type":"integer"},"state":{"type":"string"},"storeId":{"type":"string"},"trialEndsAt":{"type":"string"},"usedCredits":{"type":"integer"}},"type":"object"},"WebhookCreateRequest":{"additionalProperties":false,"description":"A receiver to register.","properties":{"events":{"description":"The order events to send to it. Repeats are ignored; the receiver gets each event at most once per order.","items":{"enum":["order.dispatched","order.parked","order.picked","order.out_for_delivery","order.delivered","order.completed","order.canceled"],"type":"string"},"minItems":1,"type":"array"},"url":{"description":"url must start with https://, reach a public address (private, loopback, link-local and other reserved addresses are refused as typed, and again when CompuDime connects), carry no user name or password, and be at most 2048 characters long.","maxLength":2048,"type":"string"}},"required":["url","events"],"type":"object"},"WebhookDeletedResponse":{"additionalProperties":true,"description":"A removed receiver.","properties":{"deleted":{"description":"Always true.","type":"boolean"},"id":{"description":"The receiver's id.","type":"string"},"requestId":{"type":"string"}},"required":["requestId","id","deleted"],"type":"object"},"WebhookDelivery":{"additionalProperties":true,"description":"One event sent, or to be sent, to a receiver.","properties":{"attempts":{"description":"Attempts made so far.","type":"integer"},"createdAt":{"description":"When the event was queued.","format":"date-time","type":"string"},"deliveredAt":{"description":"When your receiver accepted it; absent until then.","format":"date-time","type":"string"},"event":{"description":"The event: an order event or webhook.test.","type":"string"},"id":{"description":"The delivery id: id in the body and X-CompuDime-Delivery.","type":"string"},"lastError":{"description":"Why the last attempt failed; absent once delivered.","type":"string"},"lastStatus":{"description":"The HTTP status your receiver answered on the last attempt; absent when no answer came (a connection failure or a timeout).","type":"integer"},"nextAttemptAt":{"description":"When the next attempt is due; absent once delivered or dead.","format":"date-time","type":"string"},"orderId":{"description":"The order it is about; absent on a test event.","type":"string"},"state":{"description":"pending (waiting for its first attempt), failed (an attempt failed; the next one is at nextAttemptAt), delivered (your receiver answered 2xx), or dead (every retry failed; the store owner can send it again from the console).","type":"string"},"updatedAt":{"description":"When the delivery last changed.","format":"date-time","type":"string"}},"required":["id","event","state","attempts","createdAt","updatedAt"],"type":"object"},"WebhookDeliveryListResponse":{"additionalProperties":true,"description":"A receiver's newest deliveries.","properties":{"deliveries":{"items":{"$ref":"#/components/schemas/WebhookDelivery"},"type":"array"},"requestId":{"type":"string"},"webhookId":{"description":"The receiver's id.","type":"string"}},"required":["requestId","webhookId","deliveries"],"type":"object"},"WebhookListResponse":{"additionalProperties":true,"description":"Your receivers for the calling key's mode.","properties":{"limit":{"description":"How many receivers your integration may keep for this key mode.","type":"integer"},"requestId":{"type":"string"},"webhooks":{"items":{"$ref":"#/components/schemas/WebhookReceiver"},"type":"array"}},"required":["requestId","webhooks","limit"],"type":"object"},"WebhookReceiver":{"additionalProperties":true,"description":"A receiver of your integration. Never its secret.","properties":{"active":{"description":"false when the store owner or CompuDime turned it off: nothing is sent to it, and a test event is 409 webhook_inactive.","type":"boolean"},"createdAt":{"description":"When it was registered.","format":"date-time","type":"string"},"events":{"description":"The order events it is subscribed to.","items":{"type":"string"},"type":"array"},"id":{"description":"The receiver's id: the webhookId of the other receiver operations, and data.webhookId of a test event.","type":"string"},"lastDelivery":{"$ref":"#/components/schemas/WebhookDelivery","description":"Its newest delivery; absent when nothing was sent to it yet."},"mode":{"description":"The mode of the key it belongs to. A test receiver gets only the test events you send it.","enum":["live","test"],"type":"string"},"secretPrefix":{"description":"The first characters of the signing secret (whsec_ and six more), to tell secrets apart. Never more of it.","type":"string"},"secretRotatedAt":{"description":"When its secret was last rotated; absent if never.","format":"date-time","type":"string"},"updatedAt":{"description":"When it last changed.","format":"date-time","type":"string"},"url":{"description":"Where CompuDime posts the events.","type":"string"}},"required":["id","url","events","active","mode","secretPrefix","createdAt","updatedAt"],"type":"object"},"WebhookResponse":{"additionalProperties":true,"description":"One receiver.","properties":{"requestId":{"type":"string"},"webhook":{"$ref":"#/components/schemas/WebhookReceiver"}},"required":["requestId","webhook"],"type":"object"},"WebhookSecretResponse":{"additionalProperties":true,"description":"A receiver and its signing secret, answered once by POST /v1/webhooks and by POST /v1/webhooks/{webhookId}/rotate-secret.","properties":{"requestId":{"type":"string"},"secret":{"description":"The signing secret: whsec_ and 64 hex digits. Shown in this answer only.","type":"string"},"secretNote":{"description":"This signing secret is shown once, in this answer, and never again: store it now, like a password. If you lose it, rotate it (POST /v1/webhooks/{webhookId}/rotate-secret).","type":"string"},"webhook":{"$ref":"#/components/schemas/WebhookReceiver"}},"required":["requestId","webhook","secret","secretNote"],"type":"object"},"WebhookTestData":{"additionalProperties":true,"description":"What a test event carries. It is about no order.","properties":{"mode":{"description":"The receiver's key mode.","enum":["live","test"],"type":"string"},"note":{"description":"Says that this is a test event.","type":"string"},"requestId":{"description":"The requestId of that call.","type":"string"},"requestedAt":{"description":"When POST /v1/webhooks/{webhookId}/test was called.","format":"date-time","type":"string"},"webhookId":{"description":"The receiver it was sent to.","type":"string"}},"required":["webhookId","mode","requestedAt","note"],"type":"object"},"WebhookTestEvent":{"additionalProperties":true,"description":"The body of a test event. New keys may be added; ignore the ones you do not know.","properties":{"createdAt":{"description":"When the test event was queued.","format":"date-time","type":"string"},"data":{"$ref":"#/components/schemas/WebhookTestData"},"id":{"description":"The delivery id, also sent as X-CompuDime-Delivery. Retries carry the same id.","type":"string"},"type":{"enum":["webhook.test"],"type":"string"}},"required":["id","type","createdAt","data"],"type":"object"},"WebhookTestQueuedResponse":{"additionalProperties":true,"description":"The queued test event.","properties":{"delivery":{"$ref":"#/components/schemas/WebhookDelivery"},"note":{"description":"What happens next.","type":"string"},"requestId":{"type":"string"}},"required":["requestId","delivery"],"type":"object"},"ZReportResponse":{"additionalProperties":true,"properties":{"billing":{"$ref":"#/components/schemas/BillingMeta"},"businessDay":{"description":"The business day asked for.","format":"date","type":"string"},"generatedAt":{"description":"When the store agent read the data from the POS.","format":"date-time","type":"string"},"logs":{"description":"The register logs of the business day, register then log order: one per register per shift (a register normally closes one log a day). Empty when no register opened a log that day.","items":{"$ref":"#/components/schemas/PosZReportLog"},"maxItems":200,"type":"array"},"requestId":{"type":"string"},"source":{"description":"Always live: read from the store at request time.","enum":["live"],"type":"string"},"truncated":{"description":"The day has more than the 200 logs one answer carries; read it per register.","type":"boolean"}},"required":["requestId","businessDay","logs","truncated","generatedAt","source"],"type":"object"}},"securitySchemes":{"bearerAuth":{"bearerFormat":"CompuDime public API key","scheme":"bearer","type":"http"}}},"info":{"description":"Read a store's products, prices, sales, customers and more from its point of sale, and send orders into it. info.version is the date of the newest change in the changelog (https://api.compudime.com/docs/changelog). Additive changes ship any day. A breaking change ships when it is needed and is announced there the day it ships, marked Breaking; there is no fixed notice period. Where the old behaviour is kept for a while, its operations are marked deprecated and answer Deprecation and Sunset headers until it stops (https://api.compudime.com/docs/versioning). Clients must ignore fields they do not know. To try the API without a store's data, use a test key for the demo store, CompuDime Demo Market, whose data is invented and never billed (https://api.compudime.com/docs/sandbox).","title":"CompuDime Public Developer API","version":"2026-11-04"},"openapi":"3.1.0","paths":{"/healthz":{"get":{"operationId":"platform.healthz","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}},"description":"API Edge health status."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."}},"security":[],"summary":"Check API Edge health","tags":["status"],"x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-token-cost":0},"servers":[{"description":"This path is served only on the deployment's own address; the API address carries /v1/* and /openapi.json.","url":"https://compudime-public-api.fly.dev"}]},"/openapi.json":{"get":{"operationId":"platform.openapi","responses":{"200":{"description":"OpenAPI 3.1 document."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."}},"security":[],"summary":"Fetch OpenAPI document","tags":["docs"],"x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-token-cost":0}},"/readyz":{"get":{"operationId":"platform.readyz","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}},"description":"API Edge readiness status."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."}},"security":[],"summary":"Check API Edge readiness","tags":["status"],"x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-token-cost":0},"servers":[{"description":"This path is served only on the deployment's own address; the API address carries /v1/* and /openapi.json.","url":"https://compudime-public-api.fly.dev"}]},"/v1/accounting/journal-entries":{"get":{"operationId":"accounting.journal.list","parameters":[{"description":"Comma-separated accounting journal entries fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"First business day (YYYY-MM-DD, the store's calendar), inclusive. Required. A register log belongs to the business day the POS recorded on it, else the day it started (a log that closes after midnight belongs to the day it started).","in":"query","name":"from","required":true,"schema":{"format":"date","type":"string"}},{"description":"Last business day (YYYY-MM-DD), inclusive. Required; not before from and not after today. There is no limit on the span.","in":"query","name":"to","required":true,"schema":{"format":"date","type":"string"}},{"description":"How many store-days to return: any whole number of 1 or more; default 100 (one page). The store is read up to a quarter at a time, so a longer range is read in several reads, one after another, and answered at once. One answer carries at most 10,000 store-days (a safeguard on the size of one answer, not a limit on the range); a longer range ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. With format=csv the answer is written whole once read (no leading spaces, no trailers; X-Next-Cursor names the cursor). A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty. Priced by the pages of 100 store-days returned once the endpoint's meter is priced by the page.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous answer, verbatim, with the same from and to. Omit for the first page; an empty nextCursor means the range is done.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"description":"json (default) or csv. The CSV is one row per journal line with the entry's header on every row (UTF-8 without a byte order mark, RFC 4180 quoting, CRLF line ends); fields does not apply to it; its billing is in the X-Credits-* headers and its next page's cursor in X-Next-Cursor.","in":"query","name":"format","required":false,"schema":{"default":"json","enum":["json","csv"],"type":"string"}},{"description":"The largest rounding difference, in dollars, a ready entry may post to Sales/Adjustment. Default 1.00; 0 to 100.00, at most two decimals.","in":"query","name":"maxAdjustment","required":false,"schema":{"default":1,"maximum":100,"minimum":0,"type":"number"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingJournalResponse"}},"text/csv":{"schema":{"description":"Columns: external_id, status, business_day, store_code, entity, line_number, account_name, account_id, debit, credit, memo, department, category_key, name_key, revision. One row per journal line with the entry's header on every row; an entry without lines is one row with the line columns empty. UTF-8 without a byte order mark, RFC 4180 quoting, CRLF line ends.","type":"string"}}},"description":"One page of journal entries, live: each store-day's totals through the store's own account mapping, balanced or flagged. JSON, or CSV with format=csv. Needs the accounting-data permission on the API key (capability accounting-data, scope accounting.read): these reads carry cost of goods sold, which no other read returns. No key has it by default; CompuDime grants it per store and per key. There is no switch on the store machine.","headers":{"X-Next-Cursor":{"description":"On a CSV answer: the cursor of the next page; absent when the range is done.","schema":{"type":"string"}}}},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"from or to is missing or not a YYYY-MM-DD day, to is before from or after today, limit is not a whole number from 1, cursor is not one a previous answer of the same range issued, format is not json or csv, fields was sent with format=csv, or maxAdjustment is not 0 to 100.00 with at most two decimals (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key does not carry the accounting-data permission (scope accounting.read), or the store is not enabled for it (rejected before billing)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to the register's close-out totals (rejected before billing). agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. accounting_unsupported: the store's POS database has no register log table these reads can use. accounting_mapping_missing: the store has no account mapping (TisWin3's QuickBooks sales mapping, QBSalesReceiptItems); GET /v1/accounting/mapping lists the keys to map. accounting_mapping_invalid: the stored mapping is not readable XML. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the journal entries (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List mapped journal entries by store-day live","tags":["accounting","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"}},"x-compudime-capability-id":"accounting-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"accounting","x-compudime-field-catalog":{"fields":["businessDay","externalId","revision","status","entity","class","store","memo","revenueView","logs","lines","totals","adjustment","skipped","warnings","mapping"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"accounting.journal.default","standardFields":["businessDay","externalId","revision","status","entity","class","store","memo","revenueView","logs","lines","totals","adjustment","skipped","warnings","mapping"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"accounting.read","x-compudime-token-cost":1}},"/v1/accounting/mapping":{"get":{"operationId":"accounting.mapping.get","parameters":[{"description":"Comma-separated accounting mapping fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingMappingResponse"}}},"description":"Every key the store can produce with its current mapping or null, and whether it moved money in the last 90 days. Needs the accounting-data permission on the API key (capability accounting-data, scope accounting.read): these reads carry cost of goods sold, which no other read returns. No key has it by default; CompuDime grants it per store and per key. There is no switch on the store machine."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key does not carry the accounting-data permission (scope accounting.read), or the store is not enabled for it (rejected before billing)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to the register's close-out totals (rejected before billing). agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. accounting_unsupported: the store's POS database has no register log table these reads can use. accounting_mapping_invalid: the stored mapping is not readable XML. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the accounting mapping read (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get the store's account mapping keys live","tags":["accounting","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"}},"x-compudime-capability-id":"accounting-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"accounting","x-compudime-field-catalog":{"fields":["store","settings","mapping","mappedRevenueViews","window","keys","seenUnmapped"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"accounting.mapping.default","standardFields":["store","settings","mapping","mappedRevenueViews","window","keys","seenUnmapped"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"accounting.read","x-compudime-token-cost":1}},"/v1/accounting/sales-summaries":{"get":{"operationId":"accounting.summaries.list","parameters":[{"description":"Comma-separated accounting sales summaries fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"First business day (YYYY-MM-DD, the store's calendar), inclusive. Required. A register log belongs to the business day the POS recorded on it, else the day it started (a log that closes after midnight belongs to the day it started).","in":"query","name":"from","required":true,"schema":{"format":"date","type":"string"}},{"description":"Last business day (YYYY-MM-DD), inclusive. Required; not before from and not after today. There is no limit on the span.","in":"query","name":"to","required":true,"schema":{"format":"date","type":"string"}},{"description":"How many store-days to return: any whole number of 1 or more; default 100 (one page). The store is read up to a quarter at a time, so a longer range is read in several reads, one after another, and answered at once. One answer carries at most 10,000 store-days (a safeguard on the size of one answer, not a limit on the range); a longer range ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. With format=csv the answer is written whole once read (no leading spaces, no trailers; X-Next-Cursor names the cursor). A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty. Priced by the pages of 100 store-days returned once the endpoint's meter is priced by the page.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous answer, verbatim, with the same from and to. Omit for the first page; an empty nextCursor means the range is done.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountingSummariesResponse"}}},"description":"One page of store-days, live: each day's register close-out totals as labeled lines keyed like TisWin3's QuickBooks mapping, with the drawer checks, a status, a stable external id and a revision. Needs the accounting-data permission on the API key (capability accounting-data, scope accounting.read): these reads carry cost of goods sold, which no other read returns. No key has it by default; CompuDime grants it per store and per key. There is no switch on the store machine."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"from or to is missing or not a YYYY-MM-DD day, to is before from or after today, limit is not a whole number from 1, or cursor is not one a previous answer of the same range issued (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key does not carry the accounting-data permission (scope accounting.read), or the store is not enabled for it (rejected before billing)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to the register's close-out totals (rejected before billing). agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. accounting_unsupported: the store's POS database has no register log table these reads can use. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the accounting summary (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List register-log sales summaries by store-day live","tags":["accounting","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"accounting.read"}},"x-compudime-capability-id":"accounting-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"accounting","x-compudime-field-catalog":{"fields":["businessDay","status","externalId","revision","store","logs","departmentTotals","cogsSource","lines","checks"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"accounting.summaries.default","standardFields":["businessDay","status","externalId","revision","store","logs","departmentTotals","cogsSource","lines","checks"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"accounting.read","x-compudime-token-cost":1}},"/v1/brands":{"get":{"operationId":"catalog.brands.list","parameters":[{"description":"Comma-separated brands fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many brands to return: any whole number of 1 or more; default 100 (one page). The store is read 500 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only the brands the POS changed at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A row changes whenever a product gains or loses its value, because its productCount changes; on a list built from the products it also changes whenever a product carrying the value changes. A store whose list keeps no modification time answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandListResponse"}}},"description":"One live page of the brands the store's products carry, each with its product count, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, or modifiedSince is not an RFC3339 timestamp (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and a store-wide list cannot be narrowed to it (rejected before billing). modified_since_unsupported: the brand list keeps no modification time; list without modifiedSince. brands_unsupported: the store's POS database keeps no brand list (TisWin3 keeps one from database version 1.308) and its products carry no brand field to build one from, or more than 10,000 distinct brands. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the brand list (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's brands live","tags":["reference","catalog","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"reference","x-compudime-field-catalog":{"fields":["name","productCount","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"catalog.brands.default","standardFields":["name","productCount","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"catalog.reference.read","x-compudime-token-cost":1}},"/v1/capabilities":{"get":{"operationId":"platform.capabilities.list","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilityListResponse"}}},"description":"Store-visible capability catalog."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List public API capabilities","tags":["platform","capabilities"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.capabilities.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.capabilities.read"}},"x-compudime-family":"platform","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"platform.capabilities.read","x-compudime-token-cost":0}},"/v1/catalog/snapshots/current":{"get":{"operationId":"catalog.snapshots.current","parameters":[{"description":"Comma-separated catalog snapshot fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogSnapshot"}}},"description":"Current catalog snapshot metadata."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested catalog resource was not found."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get current catalog snapshot","tags":["catalog","snapshots"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.snapshots.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.snapshots.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"catalog","x-compudime-field-catalog":{"fields":["snapshotId","storeId","source","generatedAt","lastSuccessAt","productCount","state","stale","warnings"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"catalog.snapshots.default","standardFields":["snapshotId","storeId","source","generatedAt","lastSuccessAt","productCount","state","stale","warnings"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.snapshots.read","x-compudime-token-cost":1}},"/v1/categories":{"get":{"operationId":"catalog.categories.list","parameters":[{"description":"Comma-separated categories fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many rows to return: any whole number of 1 or more; default 100 (one page). The store is read 500 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only one list: department (the product field department), category (category) or subCategory (subCategory, each row naming its category in parent). Omit for all three, which come in that order.","in":"query","name":"type","required":false,"schema":{"enum":["department","category","subCategory"],"type":"string"}},{"description":"Only the rows the POS changed at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A row changes whenever a product gains or loses its value, because its productCount changes; on a list built from the products it also changes whenever a product carrying the value changes. A store whose list keeps no modification time answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryListResponse"}}},"description":"One live page of the store's departments, categories and sub-categories (in that order), each with its product count, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued (or was issued for another type), type is not department, category or subCategory, or modifiedSince is not an RFC3339 timestamp (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and a store-wide list cannot be narrowed to it (rejected before billing). modified_since_unsupported: one of the asked lists keeps no modification time; list without modifiedSince. categories_unsupported: the store's POS database keeps no list for an asked type (TisWin3 keeps them from database version 1.308) and its products carry no such field to build one from, or more than 10,000 distinct values of it. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the category list (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's departments, categories and sub-categories live","tags":["reference","catalog","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"reference","x-compudime-field-catalog":{"fields":["type","name","parent","productCount","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"catalog.categories.default","standardFields":["type","name","parent","productCount","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"catalog.reference.read","x-compudime-token-cost":1}},"/v1/customers":{"get":{"operationId":"customers.list","parameters":[{"description":"Comma-separated customers fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many customers to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty. At access level own a page holds at most 25 customers whatever limit asks (x-compudime-access-level).","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only customers modified at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A store whose POS keeps no customer modification time answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerListResponse"}}},"description":"One live page of the store's customers in a stable order, with the cursor for the next page. At access level own, only the customers linked to this integration, in phone order."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued (at this integration's access level), or modifiedSince is not an RFC3339 timestamp (code bad_request); or a requested field is not allowed, including account without the owner's grant (code field_not_allowed). Rejected before billing, except a cursor of the other access level, which is refused once read and released, never charged."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store cannot answer the request as asked: modified_since_unsupported (its POS keeps no customer modification time; list without modifiedSince) or account_unsupported (its POS has no customer account figures; request without account). The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the customer list (code store_error): the agent answered an error, its customer reads are not enabled, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's customers live","tags":["customers","live"],"x-compudime-access-level":{"all":{"effect":"Pages the store's whole customer file.","scope":"customers.read.all"},"narrowsRows":true,"own":{"effect":"Pages only the customers linked to this integration: the customers its own orders (POST /v1/orders) landed on in the store's POS, matched by the customer's main phone. They come in phone order, at most 25 a page whatever limit asks, and a page can hold fewer (even none) while nextCursor is set, when a linked customer is no longer on file. The cursor is this level's own; a cursor issued at the other level is a 400. modifiedSince keeps the linked customers modified at or after it, and every linked customer without a modifiedAt. An integration with no linked customer gets an empty page.","scope":"customers.read.self"}},"x-compudime-capability-id":"customer-access","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"customers","x-compudime-field-catalog":{"fields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"],"gatedFields":["account"],"gatedFieldsNote":"gatedFields are sensitive: they are not in fields, never part of an omitted fields or of *, and resolve only when the request names them AND the store owner has allowed sensitive customer fields for this integration (off by default). Without that, naming one is a free 400 field_not_allowed. A named gated field counts as one field for pricing.","note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"customers.default","standardFields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"customers.read.all","x-compudime-token-cost":1}},"/v1/customers/lookup":{"get":{"operationId":"customers.lookup","parameters":[{"description":"10-digit US phone number; formatting characters and a leading +1 are accepted.","in":"query","name":"phone","required":true,"schema":{"type":"string"}},{"description":"Comma-separated customers fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerLookupResponse"}}},"description":"Projected POS customer matches for the phone number (found:false with no matches). At access level own, only the matches linked to this integration."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The phone query parameter is missing or not a 10-digit US number."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the lookup (code store_error)."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS did not answer inside the lookup ceiling (code store_timeout)."}},"security":[{"bearerAuth":[]}],"summary":"Look up POS customers by phone","tags":["customers"],"x-compudime-access-level":{"all":{"effect":"Returns every customer on file for the phone.","scope":"customers.read.all"},"narrowsRows":true,"own":{"effect":"Returns only the customers linked to this integration among the phone's matches. When none is linked the answer is found:false with no customers, exactly like a phone the store does not know, so it never confirms that a customer exists.","scope":"customers.read.self"}},"x-compudime-capability-id":"customer-access","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"customers","x-compudime-field-catalog":{"fields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"customers.default","standardFields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"customers.read.all","x-compudime-token-cost":1}},"/v1/customers/{posCustomerId}":{"get":{"operationId":"customers.get","parameters":[{"description":"The POS customer id (posCustomerId on any customer row), percent-encoded. 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ -; anything else is a free 400 before billing. The literal id lookup is not addressable here (it is the phone lookup route).","in":"path","name":"posCustomerId","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@-]{0,39}$","type":"string"}},{"description":"Comma-separated customers fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomerResponse"}}},"description":"The live customer with that POS customer id (at access level own, only a customer linked to this integration)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The posCustomerId is missing, longer than 40 characters, or contains characters outside the documented set (code bad_request); or a requested field is not allowed, including account without the owner's grant (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no customer with that POS customer id, or, at access level own, the customer is not linked to this integration; the two are answered alike (code customer_not_found; the register's anonymous walk-in accounts count as not found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"account was requested and the store's POS has no customer account figures (code account_unsupported). The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the customer read (code store_error): the agent answered an error, its customer reads are not enabled, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get a customer live by POS customer id","tags":["customers","live"],"x-compudime-access-level":{"all":{"effect":"Returns any customer of the store.","scope":"customers.read.all"},"narrowsRows":true,"own":{"effect":"Returns the customer only when it is linked to this integration (its main phone is the phone of one of this integration's orders that landed in the POS). Any other customer is 404 customer_not_found, exactly like a customer the store does not have, so the answer never confirms that a customer exists.","scope":"customers.read.self"}},"x-compudime-capability-id":"customer-access","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"customers","x-compudime-field-catalog":{"fields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"],"gatedFields":["account"],"gatedFieldsNote":"gatedFields are sensitive: they are not in fields, never part of an omitted fields or of *, and resolve only when the request names them AND the store owner has allowed sensitive customer fields for this integration (off by default). Without that, naming one is a free 400 field_not_allowed. A named gated field counts as one field for pricing.","note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"customers.default","standardFields":["posCustomerId","firstName","lastName","company","addressLine1","addressLine2","city","state","postalCode","email","phones","custLevel","cat","tagList","matchedOn","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"customers.read.all","x-compudime-token-cost":1}},"/v1/delivery/routes":{"get":{"operationId":"delivery.routes.list","parameters":[{"description":"Comma-separated delivery routes fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeliveryRouteListResponse"}}},"description":"The store's delivery routes, live, each with its customer count and its open-invoice count."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and a store-wide route count cannot be narrowed to it (rejected before billing). routes_unsupported: the store's POS keeps no delivery route on its customers (the reservation is released, nothing is charged)."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the delivery route list (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's delivery routes live","tags":["delivery","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"delivery","x-compudime-field-catalog":{"fields":["route","customers","openInvoices"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"delivery.routes.default","standardFields":["route","customers","openInvoices"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/inventory/onhand":{"get":{"operationId":"inventory.onhand.list","parameters":[{"description":"Comma-separated inventory on-hand fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"Only these product codes: a comma-separated list of at most 200, each 1-40 letters, digits or dashes. Omitted: every product with an on-hand row. A key with a product-code row scope reads only codes inside it (codes outside it are dropped without a trace), and a key whose scope is not a plain code list must name codes.","in":"query","name":"codes","required":false,"schema":{"pattern":"^[A-Za-z0-9-]{1,40}(,[A-Za-z0-9-]{1,40}){0,199}$","type":"string"}},{"description":"An inventory location name (1-20 letters, digits, spaces or . _ -). Omitted: the store totals, whose rows carry location \"\". A name the store does not have answers 404 location_not_found; a store that keeps no on-hand per location answers 422 locations_unsupported.","in":"query","name":"location","required":false,"schema":{"maxLength":20,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._-]{0,19}$","type":"string"}},{"description":"How many rows to return: any whole number of 1 or more; default 100 (one page). The store is read 500 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same codes and location. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnHandListResponse"}}},"description":"One live page of on-hand quantities in product code order, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"codes is not a list of at most 200 product codes, location is not a location name, limit is not a whole number of 1 or more, or cursor is not one a previous page issued (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no inventory location with that name (code location_not_found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key's row scope cannot be applied to this read (a brand, department or category scope cannot be evaluated on an on-hand row; a product-code scope that is not a plain code list needs the codes parameter), rejected before billing. locations_unsupported: the store's POS keeps no on-hand per location; read the store totals without location (the reservation is released)."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the on-hand read (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List on-hand quantities live","tags":["inventory","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"inventory","x-compudime-field-catalog":{"fields":["productCode","location","onHand","updatedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"inventory.onhand.default","standardFields":["productCode","location","onHand","updatedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/invoices":{"get":{"operationId":"invoices.list","parameters":[{"description":"Comma-separated invoices fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many invoices to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only invoices modified at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A store whose POS keeps no invoice modification time answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Only invoices due on or after this day (YYYY-MM-DD, the store's calendar). Must not be after dueTo.","in":"query","name":"dueFrom","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only invoices due on or before this day (YYYY-MM-DD, inclusive: a due time of day on that day still counts).","in":"query","name":"dueTo","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only invoices with exactly this POS status, matched without regard to case (the POS writes Created, Picked, Completed and Processed; a store may use others). 1-25 letters, digits, spaces or . _ -","in":"query","name":"status","required":false,"schema":{"maxLength":25,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._-]{0,24}$","type":"string"}},{"description":"Only invoices carrying exactly this external order id (the placing system's own id, as the POS stored it; the POS strips leading zeros). Stores below TisWin3 database version 1.324 keep no external id and answer 422 filter_unsupported.","in":"query","name":"externalId","required":false,"schema":{"maxLength":128,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:#@+-]{0,127}$","type":"string"}},{"description":"Only invoices placed by this system, matched without regard to case; orders placed through POST /v1/orders carry CDAPI:\u003cintegration id\u003e. The POS keeps only the first characters of each value (10 of the processor code and 25 of the external id on current TisWin3 databases); the store compares what you send the way the POS stored it, so the full values you sent at intake work. Stores below TisWin3 database version 1.324 answer 422 filter_unsupported.","in":"query","name":"processorCode","required":false,"schema":{"maxLength":50,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._:#\u0026+@-]{0,49}$","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceListResponse"}}},"description":"One live page of the store's POS invoice headers in a stable order, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, modifiedSince is not an RFC3339 timestamp, dueFrom or dueTo is not a YYYY-MM-DD day or dueFrom is after dueTo, or status, externalId or processorCode is not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to invoices (rejected before billing). modified_since_unsupported: the store's POS keeps no invoice modification time; list without modifiedSince. filter_unsupported: the store's POS has no column to answer one of the filters (dueFrom / dueTo, status, externalId, processorCode; the last two exist only from TisWin3 database version 1.324); list without it. invoices_unsupported: the store keeps its orders in legacy tables the invoice reads cannot answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the invoice list (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's POS invoices live","tags":["invoices","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"invoices","x-compudime-field-catalog":{"fields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"invoices.default","standardFields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/invoices/external/{externalId}":{"get":{"operationId":"invoices.get_by_external","parameters":[{"description":"The placing system's own order id as the POS stored it (externalId on an invoice row), matched exactly, percent-encoded. Note the POS strips leading zeros from a feed's order id. 1-128 characters: a letter or digit, then letters, digits or . _ : # @ + -; anything else is a free 400 before billing. The POS keeps only the first characters of each value (10 of the processor code and 25 of the external id on current TisWin3 databases); the store compares what you send the way the POS stored it, so the full values you sent at intake work. When more than one invoice carries the pair as the POS keeps it (the POS does not enforce uniqueness), the read answers 409 invoice_ambiguous instead of choosing one.","in":"path","name":"externalId","required":true,"schema":{"maxLength":128,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._:#@+-]{0,127}$","type":"string"}},{"description":"Required. The code of the system that placed the order (processorCode on an invoice row), matched without regard to case; orders placed through POST /v1/orders carry CDAPI:\u003cintegration id\u003e. 1-50 characters: a letter or digit, then letters, digits, spaces or . _ : # \u0026 + @ -. Missing or malformed is a free 400 before billing. The POS keeps only the first characters of each value (10 of the processor code and 25 of the external id on current TisWin3 databases); the store compares what you send the way the POS stored it, so the full values you sent at intake work.","in":"query","name":"processorCode","required":true,"schema":{"maxLength":50,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._:#\u0026+@-]{0,49}$","type":"string"}},{"description":"Comma-separated invoice detail fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponse"}}},"description":"The live invoice an order feed stamped with that processor code and external id, with its lines and its delivery record."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The externalId is missing or not of the documented shape, or processorCode is missing or not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no invoice carrying that processorCode and externalId (code invoice_not_found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"More than one invoice carries that processorCode and externalId as the POS keeps them (code invoice_ambiguous); read the invoice by its POS invoice id. The reservation is released, nothing is charged."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to invoices (rejected before billing). filter_unsupported: the store's POS keeps no external order id or processor code (both exist only from TisWin3 database version 1.324); read the invoice by its POS invoice id. invoices_unsupported: the store keeps its orders in legacy tables the invoice reads cannot answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the invoice read (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get an invoice live by the placing system's order id","tags":["invoices","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"invoices","x-compudime-field-catalog":{"fields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt","lines","linesTruncated","delivery"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"invoices.detail","standardFields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt","lines","linesTruncated","delivery"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/invoices/{posInvoiceId}":{"get":{"operationId":"invoices.get","parameters":[{"description":"The POS invoice id (invoiceId on any invoice row), percent-encoded as ONE path segment: a / inside the id must be sent as %2F. 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -; anything else, and an unencoded /, is a free 400 before billing. The id alone addresses the invoice (no customer id is needed or accepted). The literal id external is not addressable here (it is the lookup-by-feed-identity route).","in":"path","name":"posInvoiceId","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Comma-separated invoice detail fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvoiceResponse"}}},"description":"The live invoice with that POS invoice id, with its lines and its delivery record."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The posInvoiceId is missing, longer than 40 characters, contains characters outside the documented set, or carries an unencoded / (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no invoice with that POS invoice id (code invoice_not_found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to invoices (rejected before billing). invoices_unsupported: the store keeps its orders in legacy tables the invoice reads cannot answer (the reservation is released)."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the invoice read (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get an invoice live by POS invoice id","tags":["invoices","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"invoices","x-compudime-field-catalog":{"fields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt","lines","linesTruncated","delivery"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"invoices.detail","standardFields":["invoiceId","number","orderNumber","customerId","anonymousCustomer","date","due","status","payType","orderDept","deliveryMethod","deliveryTime","route","routeSeq","processorCode","externalId","source","totals","taxRate1","taxRate2","timeline","modifiedAt","lines","linesTruncated","delivery"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/me":{"get":{"operationId":"platform.me.get","responses":{"200":{"content":{"application/json":{"example":{"requestId":"req_0123456789abcdef","key":{"prefix":"cd_live_","mode":"live","kind":"genie"},"integration":{"integrationId":"5f1c2d3e-4a5b-4c6d-8e7f-90a1b2c3d4e5","displayName":"Shelf labels","capabilityId":"catalog-feed","capabilities":["catalog-feed"],"accessLevel":"own","billingClass":"charged"},"store":{"storeId":"corner_market","displayName":"Corner Market"},"fieldPolicy":{"policyId":"corner_market:catalog.products.default:v1","version":1,"resources":[{"resource":"catalog.products.default","endpoints":["catalog.products.list","catalog.products.get"],"source":"policy","fields":["productCode","upc","unitsPerCase","description","smallDescription","brand","department","category","size","pack","price","priceQty","taxable","active","lastModifiedUtc","inactive","lastSold"],"defaultFields":["productCode","upc","description","brand","price"]},{"resource":"catalog.products.live","endpoints":["catalog.products.lookup"],"source":"catalog","fields":["productCode","description","price","activePrice","onHand","upc","unitsPerCase","smallDescription","brand","department","category","subCategory","size","pack","casePrice","packagePrice","packageQty","salePrice","saleActive","caseSalePrice","caseSaleActive","packageSalePrice","packageSaleQty","packageSaleActive","priceEmbedded","scale","autoTare","tare","noSale","inactive","taxable","foodStamp","wic","matchType","matchField","matchedCode","lastSold","lastModifiedUtc"],"defaultFields":["productCode","description","price","activePrice","onHand"]}]},"rateLimit":{"requestsPerMinute":120,"burst":120},"credits":{"storeId":"corner_market","planId":"starter","state":"active","cardState":"valid","overageEnabled":false,"overageCapCredits":0,"currentPeriod":"2026-10","billingMode":"manual","usedCredits":212,"includedCredits":1000,"overageCredits":0,"baseCredits":212,"extraFieldCredits":0,"pendingCredits":0,"sandboxUsedCredits":0,"sandboxIncludedCredits":500}},"schema":{"$ref":"#/components/schemas/MeResponse"}}},"description":"Who the calling key is: its display prefix, mode (live or test) and kind (genie for cd_ keys, compuconnect for cc_ keys); its integration (capability, access level, billing class); its store; for each resource the key can read, the fields it may request and the ones an omitted fields returns; its per-key rate limit; and, for the store's own keys, the store's credits for the month, as GET /v1/usage/current reports them without the per-endpoint breakdown. A key your organization holds for a store (a developer's key under the owner's approval, for instance) never sees the store's plan or credits: credits is left out, creditsNote says its calls are billed to your organization (or to the store, when the owner chose to pay), and usageUrl links your organization's usage at https://account.compudime.com/usage. Never the key itself. When billing cannot be read the answer is still 200, with credits left out and creditsNote saying so. Free; a good first call."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Describe the calling key","tags":["platform","me"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.me.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.me.read"}},"x-compudime-family":"platform","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"platform.me.read","x-compudime-token-cost":0}},"/v1/orders":{"post":{"description":"Sends an order into the store's POS. A live key's order is answered 202 once it is accepted into the queue (dispatchState pending_pos_adapter); it then reads dispatched when it landed in the POS, or parked when it could not. A test key's order (a key that starts with cc_test_ or cd_test_) is validated exactly like a live key's and answered with the same 202 and body, but it is simulated and never reaches the store: its orderId starts with test_, its dispatchState is simulated (final: it never changes), the billing block says mode test, and no webhook is sent for it. The checks only the store itself makes (each productCode looked up in its POS, the price it charges, the store agent's support for shipTo and for lines without a unitPrice) are not run for a test order. Sending the same Idempotency-Key or externalOrderId again returns the same simulated order. A test key reads only its integration's simulated orders and a live key only its live ones: an order of the other mode is 404 order_not_found.","operationId":"orders.create","parameters":[{"description":"Safe caller-generated identifier used to prevent duplicate order intake and duplicate billing on retries.","in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"externalOrderId":"web-1001","customer":"Pickup customer","notes":"Paid online","orderMethod":"pickup","lines":[{"productCode":"SKU-100","quantity":2,"unitPrice":"3.99"}]},"schema":{"$ref":"#/components/schemas/OrderCreateRequest"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatus"}}},"description":"Order intake request accepted into the durable queue; a test key's order is validated and simulated instead (dispatchState simulated) and never reaches the store."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The order request body is invalid, or its externalOrderId or Idempotency-Key already names an order your integration sent with a key of the other mode (live or test)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Create order intake request","tags":["orders"],"x-compudime-access-level":{"all":{"effect":"The order belongs to this integration at either level, and only this integration reads it back.","scope":"orders.write"},"narrowsRows":false,"own":{"effect":"The order belongs to this integration at either level, and only this integration reads it back.","scope":"orders.write"}},"x-compudime-capability-id":"order-intake","x-compudime-family":"orders","x-compudime-pricing":{"baseCost":16,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.write","x-compudime-token-cost":16}},"/v1/orders/external/{externalOrderId}":{"get":{"description":"Where an order your integration sent stands. A test key reads only its integration's simulated orders and a live key only its live ones: an order of the other mode is 404 order_not_found.","operationId":"orders.get_by_external","parameters":[{"description":"The externalOrderId the order was created with, exactly as sent on POST /v1/orders. 1-128 characters: a letter or digit, then letters, digits, dots, underscores or dashes (the Idempotency-Key shape); anything else is a free 400 before billing. The lookup is scoped to the calling integration. An order whose externalOrderId is outside this shape is readable by orderId only.","in":"path","name":"externalOrderId","required":true,"schema":{"maxLength":128,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$","type":"string"}},{"description":"Comma-separated orders fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatus"}}},"description":"The order and where it stands on its way to the POS: dispatchState pending_pos_adapter (queued), dispatched (in the POS), parked (not sent, with the reason) or simulated (a test key's, final)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The externalOrderId is missing, longer than 128 characters, or contains characters other than letters, digits, dots, underscores and dashes. Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"This integration has no order with that externalOrderId (code order_not_found; the reservation is released, nothing is charged)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get order intake status by external order id","tags":["orders"],"x-compudime-access-level":{"all":{"effect":"Only the orders this integration created, at either level: all does not widen the order reads.","scope":"orders.read"},"narrowsRows":false,"own":{"effect":"Only the orders this integration created, at either level: all does not widen the order reads.","scope":"orders.read"}},"x-compudime-capability-id":"order-intake","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"orders","x-compudime-field-catalog":{"fields":["orderId","externalOrderId","status","dispatchState","createdAt","updatedAt","orderMethod","shipTo","invoice","storePrices","storeDiscount","fulfillment"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"orders.default","standardFields":["orderId","externalOrderId","status","dispatchState","createdAt","updatedAt","orderMethod","shipTo","invoice","storePrices","storeDiscount","fulfillment"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.read","x-compudime-token-cost":1}},"/v1/orders/{orderId}":{"get":{"description":"Where an order your integration sent stands. A test key reads only its integration's simulated orders and a live key only its live ones: an order of the other mode is 404 order_not_found.","operationId":"orders.get","parameters":[{"description":"The orderId returned by POST /v1/orders.","in":"path","name":"orderId","required":true,"schema":{"type":"string"}},{"description":"Comma-separated orders fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderStatus"}}},"description":"The order and where it stands on its way to the POS: dispatchState pending_pos_adapter (queued), dispatched (in the POS), parked (not sent, with the reason) or simulated (a test key's, final)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The order intake request was not found."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get order intake status","tags":["orders"],"x-compudime-access-level":{"all":{"effect":"Only the orders this integration created, at either level: all does not widen the order reads.","scope":"orders.read"},"narrowsRows":false,"own":{"effect":"Only the orders this integration created, at either level: all does not widen the order reads.","scope":"orders.read"}},"x-compudime-capability-id":"order-intake","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"orders","x-compudime-field-catalog":{"fields":["orderId","externalOrderId","status","dispatchState","createdAt","updatedAt","orderMethod","shipTo","invoice","storePrices","storeDiscount","fulfillment"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"orders.default","standardFields":["orderId","externalOrderId","status","dispatchState","createdAt","updatedAt","orderMethod","shipTo","invoice","storePrices","storeDiscount","fulfillment"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.read","x-compudime-token-cost":1}},"/v1/products":{"get":{"operationId":"catalog.products.list","parameters":[{"description":"Comma-separated catalog products fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"Cursor returned from the previous product page.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"description":"How many products to return: any whole number of 1 or more; default 100 (one page). One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing): a larger limit answers 10,000 and nextCursor. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"Only return products modified at or after this timestamp (compared with lastModifiedUtc), plus every product whose modification time is unknown (lastModifiedUtc empty), which is always returned: it cannot be shown unchanged, so an incremental sync reads it again. Rows are keyed by productCode, so reading one again is harmless. For the next call pass the largest lastModifiedUtc you have received minus one hour, not your own clock: lastModifiedUtc runs on the store's own clock, so no clock difference can skip a change, and the hour covers the hour the store's clocks go back in the fall.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Whether to list products the product file flags inactive (inactive: true). Default false: the list leaves them out, and a product whose flag the store's agent has not reported yet (inactive: null) is listed. true lists every product, inactive ones included (the list's default until 2026-10-07). Pass the same value on every page of one listing (or leave it out on every page), as with modifiedSince: the cursor continues the listing it came from. With the default, a product that becomes inactive stops appearing, even with modifiedSince; to see the change, read with includeInactive=true. true or false only; anything else is a free 400.","in":"query","name":"includeInactive","required":false,"schema":{"default":false,"type":"boolean"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductListResponse"}}},"description":"Projected catalog product page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request query is invalid."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List catalog products","tags":["catalog","products"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"catalog","x-compudime-field-catalog":{"aliases":{"unitsPerCase":"upc"},"aliasesNote":"aliases maps a second name to the field it renames. Both names return the same value with the same type, a key that may see one may see both, and a request that names both is counted and priced as one field. The renamed field is deprecated in the response schema; move to the second name.","fieldPolicy":"catalog.products.default","fields":["productCode","upc","unitsPerCase","description","smallDescription","brand","department","category","size","pack","price","priceQty","taxable","active","lastModifiedUtc","inactive","lastSold"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"field_count","resource":"catalog.products.default","standardFields":["productCode","upc","description","smallDescription","brand"]},"x-compudime-field-policy":"catalog.products.default","x-compudime-pricing":{"baseCost":1,"extraFieldCost":1,"includedFields":5,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"catalog.products.read","x-compudime-token-cost":1}},"/v1/products/lookup/{code}":{"get":{"operationId":"catalog.products.lookup","parameters":[{"description":"Any code the register resolves: the product code, a UPC with or without check digit, an alias, a case code or a price/weight-embedded barcode. 1-40 letters, digits or dashes; anything else is a free 400 before billing.","in":"path","name":"code","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9-]{1,40}$","type":"string"}},{"description":"Comma-separated live products fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductLookupResponse"}}},"description":"The live product the code resolves to at the store, with the prices the register charges right now and the on-hand quantity."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The code is missing, longer than 40 characters, or contains characters other than letters, digits and dashes. Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"No product resolves to the code at the store, or the resolved product is outside the key's row scope (code product_not_found in both cases; the reservation is released, nothing is charged)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the lookup (code store_error): TisDsServ answered an error, the agent build predates this operation, or the store's own 4 s ceiling fired. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the lookup ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Look up a product live by any code","tags":["catalog","products","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"catalog","x-compudime-field-catalog":{"aliases":{"unitsPerCase":"upc"},"aliasesNote":"aliases maps a second name to the field it renames. Both names return the same value with the same type, a key that may see one may see both, and a request that names both is counted and priced as one field. The renamed field is deprecated in the response schema; move to the second name.","fields":["productCode","description","price","activePrice","onHand","upc","unitsPerCase","smallDescription","brand","department","category","subCategory","size","pack","casePrice","packagePrice","packageQty","salePrice","saleActive","caseSalePrice","caseSaleActive","packageSalePrice","packageSaleQty","packageSaleActive","priceEmbedded","scale","autoTare","tare","noSale","inactive","taxable","foodStamp","wic","matchType","matchField","matchedCode","lastSold","lastModifiedUtc"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"field_count","resource":"catalog.products.live","standardFields":["productCode","description","price","activePrice","onHand"]},"x-compudime-pricing":{"baseCost":5,"extraFieldCost":1,"includedFields":5,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.products.read","x-compudime-token-cost":5}},"/v1/products/{productCode}":{"get":{"operationId":"catalog.products.get","parameters":[{"description":"Store product code.","in":"path","name":"productCode","required":true,"schema":{"type":"string"}},{"description":"Comma-separated catalog products fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Product"}}},"description":"Projected catalog product."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request query is invalid."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested catalog resource was not found."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get catalog product","tags":["catalog","products"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"catalog","x-compudime-field-catalog":{"aliases":{"unitsPerCase":"upc"},"aliasesNote":"aliases maps a second name to the field it renames. Both names return the same value with the same type, a key that may see one may see both, and a request that names both is counted and priced as one field. The renamed field is deprecated in the response schema; move to the second name.","fieldPolicy":"catalog.products.default","fields":["productCode","upc","unitsPerCase","description","smallDescription","brand","department","category","size","pack","price","priceQty","taxable","active","lastModifiedUtc","inactive","lastSold"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"field_count","resource":"catalog.products.default","standardFields":["productCode","upc","description","smallDescription","brand"]},"x-compudime-field-policy":"catalog.products.default","x-compudime-pricing":{"baseCost":1,"extraFieldCost":1,"includedFields":5,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.products.read","x-compudime-token-cost":1}},"/v1/promotions":{"get":{"operationId":"promotions.list","parameters":[{"description":"Comma-separated promotions fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many promotions to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page. A page can hold fewer promotions than limit, even none, while nextCursor is set: keep paging until it is empty.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"current (the default): every promotion that has not ended, running now or not; running: only those the register applies right now (runningNow true); upcoming: only those whose begin date is after today. A promotion a store rule decides is never running or on a day: list with current to see it. Not together with activeOn.","in":"query","name":"status","required":false,"schema":{"enum":["current","running","upcoming"],"type":"string"}},{"description":"A store day (YYYY-MM-DD): only the promotions the register applies at some time of that day, by the same rules as runningNow. Not together with status.","in":"query","name":"activeOn","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only the promotions of this POS product code: its own deals and mix and match membership, and the scheduled prices of the product, its category and its brand. 1-40 characters: a letter, digit or dot, then letters, digits, spaces or . _ # \u0026 + @ / = -","in":"query","name":"productCode","required":false,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9.][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Only these types, comma-separated: sale, package, packageSale, caseSale, mixMatch, scheduledPrice. A percent sale is a sale (or package sale, case sale, scheduled price) whose mode is percent.","in":"query","name":"type","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromotionListResponse"}}},"description":"One live page of the store's promotions, each saying whether the register applies it right now, with the cursor for the next page. Catalog-feed capability, like the live product lookup: shelf prices with their terms, never a cost, a vendor or a customer's own price (customer contract prices are not promotions and are not part of this API). A store can switch live catalog reads off on its POS agent, which answers 403 store_feature_not_enabled."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, status is not current, running or upcoming, activeOn is not a YYYY-MM-DD day or is sent with status, productCode or type is not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key is not a catalog-feed key (rejected before billing). store_feature_not_enabled: the store has switched live catalog reads off on its POS agent. The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key's row scope names a field the promotions cannot be matched on (rejected before billing). promotions_unsupported: the store's POS database has no product table these reads can answer. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the promotion list (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's promotions live","tags":["catalog","promotions","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"promotions","x-compudime-field-catalog":{"fields":["promotionId","type","productCode","description","brand","department","category","unitsPerCase","regularPrice","scope","priceField","mode","price","percentOff","quantity","minQuantity","maxQuantity","maxQuantityPer","permanentChange","window","mixMatch","runningNow","status","storeRuleDecides","storeRule","undeterminedReason"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"promotions.default","standardFields":["promotionId","type","productCode","description","brand","department","category","unitsPerCase","regularPrice","scope","priceField","mode","price","percentOff","quantity","minQuantity","maxQuantity","maxQuantityPer","permanentChange","window","mixMatch","runningNow","status","storeRuleDecides","storeRule","undeterminedReason"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"catalog.products.read","x-compudime-token-cost":1}},"/v1/promotions/mix-match/{groupId}":{"get":{"operationId":"promotions.mixmatch.get","parameters":[{"description":"The mix and match group id (mixMatch.groupId on a promotion), percent-encoded as ONE path segment: a / inside the id must be sent as %2F. 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -; anything else, and an unencoded /, is a free 400 before billing.","in":"path","name":"groupId","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Comma-separated mix and match group fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MixMatchGroupResponse"}}},"description":"The live mix and match group with that id, with its members and whether each pools right now. Catalog-feed capability, like the live product lookup: shelf prices with their terms, never a cost, a vendor or a customer's own price (customer contract prices are not promotions and are not part of this API). A store can switch live catalog reads off on its POS agent, which answers 403 store_feature_not_enabled."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The groupId is missing, longer than 40 characters, contains characters outside the documented set, or carries an unencoded / (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key is not a catalog-feed key (rejected before billing). store_feature_not_enabled: the store has switched live catalog reads off on its POS agent. The reservation is released, nothing is charged."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no mix and match group with that id (code mix_match_group_not_found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and a group spans products outside any slice (rejected before billing). promotions_unsupported: the store's POS database has no mix and match table. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the mix and match read (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get a mix and match group live","tags":["catalog","promotions","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.products.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"promotions","x-compudime-field-catalog":{"fields":["groupId","description","memberCount","members","membersTruncated","bogo","runningNow"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"promotions.mixmatch.default","standardFields":["groupId","description","memberCount","members","membersTruncated","bogo","runningNow"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.products.read","x-compudime-token-cost":1}},"/v1/purchase-orders":{"get":{"operationId":"purchaseorders.list","parameters":[{"description":"Comma-separated purchase orders fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many purchase orders to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"A status CLASS, never a stored POS status: open (the POS status is New, Open or Sent: still to be received), received (Complete: the order was imported into a receiving document), canceled (Canceled) or all (the same as omitting it). Compare with statusClass on a row. The POS has no partly-received status.","in":"query","name":"status","required":false,"schema":{"enum":["open","received","canceled","all"],"type":"string"}},{"description":"Only purchase orders of exactly this POS vendor id (vendorId on a row). 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -","in":"query","name":"vendorId","required":false,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Only purchase orders dated on or after this day (YYYY-MM-DD, the store's calendar). Must not be after dateTo.","in":"query","name":"dateFrom","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only purchase orders dated on or before this day (YYYY-MM-DD, inclusive).","in":"query","name":"dateTo","required":false,"schema":{"format":"date","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderListResponse"}}},"description":"One live page of the store's vendor purchase-order headers in a stable order, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, status is not open, received, canceled or all, vendorId is not of the documented shape, or dateFrom or dateTo is not a YYYY-MM-DD day or dateFrom is after dateTo (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key's integration was not created for the purchasing-data capability, or CompuDime has not enabled that capability for the store. Rejected before billing. No other capability implies it: a sales-data key answers this too. purchasing_data_not_enabled: the key is entitled, but the store has not turned on purchasing data on its own POS agent (the store-side purchasingDataEnabled opt-in, which the store's per-item sales-data opt-in does not imply). The reservation is released, nothing is charged; ask the store to enable it."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a purchasing document (its totals and lines span every product on it); rejected before billing. filter_unsupported: the store's POS has no column to answer one of the filters (status, dateFrom / dateTo); list without it. purchaseorders_unsupported: the store's POS database has no purchase-order tables these reads can answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the purchase order list (code store_error): the agent answered an error, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's vendor purchase orders live","tags":["purchasing","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"}},"x-compudime-capability-id":"purchasing-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"purchasing","x-compudime-field-catalog":{"fields":["purchaseOrderId","number","vendorId","vendorName","vendorCode","vendorPoNumber","date","requestedShipDate","shipVia","status","statusClass","discountPercent"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"purchaseorders.default","standardFields":["purchaseOrderId","number","vendorId","vendorName","vendorCode","vendorPoNumber","date","requestedShipDate","shipVia","status","statusClass","discountPercent"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"purchasing.read","x-compudime-token-cost":1}},"/v1/purchase-orders/{posPurchaseOrderId}":{"get":{"operationId":"purchaseorders.get","parameters":[{"description":"The POS purchase order id (purchaseOrderId on any purchase-order row, and on a receiving document that received one), percent-encoded as ONE path segment: a / inside the id must be sent as %2F. 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -; anything else, and an unencoded /, is a free 400 before billing.","in":"path","name":"posPurchaseOrderId","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Comma-separated purchase order detail fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PurchaseOrderResponse"}}},"description":"The live purchase order with that POS purchase order id, with its lines (quantities in cases, costs per case)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The posPurchaseOrderId is missing, longer than 40 characters, contains characters outside the documented set, or carries an unencoded / (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key's integration was not created for the purchasing-data capability, or CompuDime has not enabled that capability for the store. Rejected before billing. No other capability implies it: a sales-data key answers this too. purchasing_data_not_enabled: the key is entitled, but the store has not turned on purchasing data on its own POS agent (the store-side purchasingDataEnabled opt-in, which the store's per-item sales-data opt-in does not imply). The reservation is released, nothing is charged; ask the store to enable it."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no purchase order with that POS purchase order id (code purchase_order_not_found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a purchasing document (its totals and lines span every product on it); rejected before billing. purchaseorders_unsupported: the store's POS database has no purchase-order tables these reads can answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the purchase order read (code store_error): the agent answered an error, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get a purchase order live by POS purchase order id","tags":["purchasing","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"}},"x-compudime-capability-id":"purchasing-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"purchasing","x-compudime-field-catalog":{"fields":["purchaseOrderId","number","vendorId","vendorName","vendorCode","vendorPoNumber","date","requestedShipDate","shipVia","status","statusClass","discountPercent","lines","linesTruncated"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"purchaseorders.detail","standardFields":["purchaseOrderId","number","vendorId","vendorName","vendorCode","vendorPoNumber","date","requestedShipDate","shipVia","status","statusClass","discountPercent","lines","linesTruncated"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"purchasing.read","x-compudime-token-cost":1}},"/v1/reasons":{"get":{"operationId":"store.reasons.list","parameters":[{"description":"Comma-separated reasons fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"Only one list: discount (the reasons the register offers for a register or customer discount) or return (the reasons it offers when a return is rung). Omit for both, which come in that order.","in":"query","name":"type","required":false,"schema":{"enum":["discount","return"],"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReasonListResponse"}}},"description":"The discount and return reasons the store's register offers, live."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"type is not discount or return (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"reasons_unsupported: the store's POS database keeps no reason list. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the reason list (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the register's discount and return reasons live","tags":["reference","store","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"reference","x-compudime-field-catalog":{"fields":["type","reason"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"store.reasons.default","standardFields":["type","reason"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.reference.read","x-compudime-token-cost":1}},"/v1/receiving":{"get":{"operationId":"receiving.list","parameters":[{"description":"Comma-separated receiving fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many receiving documents to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only receiving documents modified at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A store whose POS keeps no modification time on them answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Only receiving documents dated on or after this day (YYYY-MM-DD, the store's calendar). Must not be after dateTo.","in":"query","name":"dateFrom","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only receiving documents dated on or before this day (YYYY-MM-DD, inclusive).","in":"query","name":"dateTo","required":false,"schema":{"format":"date","type":"string"}},{"description":"Only receiving documents of exactly this POS vendor id (vendorId on a row). 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -","in":"query","name":"vendorId","required":false,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Only the receiving documents that received exactly this purchase order (purchaseOrderId on a purchase-order row). A store whose POS keeps no purchase order on a receiving document answers 422 filter_unsupported.","in":"query","name":"purchaseOrderId","required":false,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivingListResponse"}}},"description":"One live page of the store's receiving-document headers in a stable order, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, modifiedSince is not an RFC3339 timestamp, dateFrom or dateTo is not a YYYY-MM-DD day or dateFrom is after dateTo, or vendorId or purchaseOrderId is not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key's integration was not created for the purchasing-data capability, or CompuDime has not enabled that capability for the store. Rejected before billing. No other capability implies it: a sales-data key answers this too. purchasing_data_not_enabled: the key is entitled, but the store has not turned on purchasing data on its own POS agent (the store-side purchasingDataEnabled opt-in, which the store's per-item sales-data opt-in does not imply). The reservation is released, nothing is charged; ask the store to enable it."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a purchasing document (its totals and lines span every product on it); rejected before billing. modified_since_unsupported: the store's POS keeps no modification time on its receiving documents; list without modifiedSince. filter_unsupported: the store's POS has no column to answer one of the filters (dateFrom / dateTo, purchaseOrderId); list without it. receiving_unsupported: the store's POS database has no receiving tables these reads can answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the receiving list (code store_error): the agent answered an error, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's receiving documents live","tags":["purchasing","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"}},"x-compudime-capability-id":"purchasing-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"purchasing","x-compudime-field-catalog":{"fields":["receivingId","number","vendorId","vendorName","vendorCode","vendorInvoiceNumber","date","billDue","businessDay","purchaseOrderId","purchaseOrderNumber","transactionType","statusCode","quick","ignoreInventory","inventoryLocation","source","discountPercent","totals","createdAt","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"receiving.default","standardFields":["receivingId","number","vendorId","vendorName","vendorCode","vendorInvoiceNumber","date","billDue","businessDay","purchaseOrderId","purchaseOrderNumber","transactionType","statusCode","quick","ignoreInventory","inventoryLocation","source","discountPercent","totals","createdAt","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"purchasing.read","x-compudime-token-cost":1}},"/v1/receiving/{posReceivingId}":{"get":{"operationId":"receiving.get","parameters":[{"description":"The POS receiving id (receivingId on any receiving row), percent-encoded as ONE path segment: a / inside the id must be sent as %2F. 1-40 characters: a letter or digit, then letters, digits, spaces or . _ # \u0026 + @ / = -; anything else, and an unencoded /, is a free 400 before billing.","in":"path","name":"posReceivingId","required":true,"schema":{"maxLength":40,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9 ._#\u0026+@/=-]{0,39}$","type":"string"}},{"description":"Comma-separated receiving detail fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReceivingResponse"}}},"description":"The live receiving document with that POS receiving id, with its lines (ordered next to received, in cases; costs per case)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The posReceivingId is missing, longer than 40 characters, contains characters outside the documented set, or carries an unencoded / (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key's integration was not created for the purchasing-data capability, or CompuDime has not enabled that capability for the store. Rejected before billing. No other capability implies it: a sales-data key answers this too. purchasing_data_not_enabled: the key is entitled, but the store has not turned on purchasing data on its own POS agent (the store-side purchasingDataEnabled opt-in, which the store's per-item sales-data opt-in does not imply). The reservation is released, nothing is charged; ask the store to enable it."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no receiving document with that POS receiving id (code receiving_not_found; an expense invoice such as rent or utilities is not a receiving document and counts as not found). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a purchasing document (its totals and lines span every product on it); rejected before billing. receiving_unsupported: the store's POS database has no receiving tables these reads can answer. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the receiving read (code store_error): the agent answered an error, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get a receiving document live by POS receiving id","tags":["purchasing","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"purchasing.read"}},"x-compudime-capability-id":"purchasing-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"purchasing","x-compudime-field-catalog":{"fields":["receivingId","number","vendorId","vendorName","vendorCode","vendorInvoiceNumber","date","billDue","businessDay","purchaseOrderId","purchaseOrderNumber","transactionType","statusCode","quick","ignoreInventory","inventoryLocation","source","discountPercent","totals","createdAt","modifiedAt","lines","linesTruncated"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"receiving.detail","standardFields":["receivingId","number","vendorId","vendorName","vendorCode","vendorInvoiceNumber","date","billDue","businessDay","purchaseOrderId","purchaseOrderNumber","transactionType","statusCode","quick","ignoreInventory","inventoryLocation","source","discountPercent","totals","createdAt","modifiedAt","lines","linesTruncated"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"purchasing.read","x-compudime-token-cost":1}},"/v1/sales/daily":{"get":{"operationId":"sales.daily.list","parameters":[{"description":"Inclusive start business day (YYYY-MM-DD).","in":"query","name":"from","required":true,"schema":{"format":"date","type":"string"}},{"description":"Inclusive end business day (YYYY-MM-DD). Must not be before from or after today (UTC). Any span: one row per business day the platform holds in the range (coveredFrom and coveredTo on the answer say which days).","in":"query","name":"to","required":true,"schema":{"format":"date","type":"string"}},{"description":"Comma-separated sales daily totals fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesDailyResponse"}}},"description":"Daily register totals (one row per business day) as last imported by the Store Pulse sync, with sync freshness."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request query is invalid: from and to are required YYYY-MM-DD dates, from \u003c= to, and to must not be after today (UTC); any span is allowed. Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint, or the sales-bi capability is not enabled for the store (code capability_not_enabled in both cases)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge could not reach the sales data service (code internal_unavailable). Nothing is sent to the store's POS for this endpoint. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List daily register totals","tags":["sales","daily"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"customers.read.all"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"customers.read.all"}},"x-compudime-capability-id":"customer-access","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"sales","x-compudime-field-catalog":{"fields":["businessDay","tickets","netSales","returns","discounts","tax","onAccount","voidsCnt","voidsAmt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"sales.daily.default","standardFields":["businessDay","tickets","netSales","returns","discounts","tax","onAccount","voidsCnt","voidsAmt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"customers.read.all","x-compudime-token-cost":1}},"/v1/sales/movement":{"get":{"operationId":"sales.movement.list","parameters":[{"description":"Movement universe: 'register' (till sales, default) or 'delivery' (order / on-account sales).","in":"query","name":"type","required":false,"schema":{"default":"register","enum":["register","delivery"],"type":"string"}},{"description":"Inclusive start business day (YYYY-MM-DD).","in":"query","name":"from","required":true,"schema":{"format":"date","type":"string"}},{"description":"Inclusive end business day (YYYY-MM-DD), not before from. Any span: the rows come from what the platform holds (coveredFrom and coveredTo on the answer say which days).","in":"query","name":"to","required":true,"schema":{"format":"date","type":"string"}},{"description":"Comma-separated sales movement fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"Cursor returned from the previous movement page.","in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"description":"How many rows to return: any whole number of 1 or more; default 100 (one page). One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing): a larger limit answers 10,000 and nextCursor. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SalesMovementResponse"}}},"description":"Projected sales movement page (register or delivery)."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request query is invalid (type, from/to range, cursor, or limit)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key's row scope does not apply to the requested movement type."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List sales movement","tags":["sales","movement"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"sales","x-compudime-field-catalog":{"fieldPolicy":"sales.movement.default","fields":["productCode","brand","businessDay","qty","salesAmount","department","category","description","weight","lines"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"field_count","resource":"sales.movement.default","standardFields":["productCode","brand","businessDay","qty","salesAmount"]},"x-compudime-field-policy":"sales.movement.default","x-compudime-pricing":{"baseCost":1,"extraFieldCost":1,"includedFields":5,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/sales/zreport":{"get":{"operationId":"sales.zreport.get","parameters":[{"description":"The business day (YYYY-MM-DD, the store's calendar). Required. A register log belongs to the business day the POS recorded on it, else the day it started, the grouping TisWin3's register log dashboard uses.","in":"query","name":"businessDay","required":true,"schema":{"format":"date","type":"string"}},{"description":"Only the logs of this register: its code as the rows show it (register), 1-2 letters or digits. A one-digit code and the same digit with a leading 0 name the same register (1 and 01), as the register itself treats them.","in":"query","name":"register","required":false,"schema":{"pattern":"^[A-Za-z0-9]{1,2}$","type":"string"}},{"description":"Comma-separated register z report fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZReportResponse"}}},"description":"The register logs (Z tapes) of the business day, live, each with the totals the register keeps and its tender totals."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"businessDay is missing or not a YYYY-MM-DD day, or register is not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key is not a sales-data key with the sales.read scope (rejected before billing). store_feature_not_enabled: the key is entitled, but the store has not turned on per-item data for developers on its own POS agent (the same store switch as sales movement and the invoice reads); nothing changes until the store enables it. The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a register ticket or a register log (rejected before billing). agent_update_required: the store's CompuDime agent is older than this read; the store must update it. zreport_unsupported: the store's POS database has no register log table with the columns this read needs. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the Z report (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get the register Z reports of a business day live","tags":["sales","zreport","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"sales","x-compudime-field-catalog":{"fields":["register","logNumber","businessDay","closed","startedAt","endedAt","lastTransactionAt","totals","drawer","tenders"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"sales.zreport.default","standardFields":["register","logNumber","businessDay","closed","startedAt","endedAt","lastTransactionAt","totals","drawer","tenders"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/store":{"get":{"operationId":"store.profile.get","parameters":[{"description":"Comma-separated store profile fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoreProfileResponse"}}},"description":"The store's business profile, live: its name and contact block as printed on its receipts, its tax rates and its POS database version."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"store_profile_unsupported: the store's POS database keeps no store settings the profile can be read from. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the store profile (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get the store's business profile live","tags":["reference","store","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"reference","x-compudime-field-catalog":{"fields":["name","nameLine2","addressLine1","addressLine2","city","state","postalCode","phone","fax","email","website","taxRates","currency","timeZone","utcOffset","databaseVersion"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"store.profile.default","standardFields":["name","nameLine2","addressLine1","addressLine2","city","state","postalCode","phone","fax","email","website","taxRates","currency","timeZone","utcOffset","databaseVersion"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"catalog.reference.read","x-compudime-token-cost":1}},"/v1/tags":{"get":{"operationId":"catalog.tags.list","parameters":[{"description":"Comma-separated tags fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"How many tags to return: any whole number of 1 or more; default 100 (one page). The store is read 500 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same filters. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"pattern":"^WyJ[A-Za-z0-9_-]{1,509}$","type":"string"}},{"description":"Only the tags the POS changed at or after this RFC3339 timestamp (incremental sync; compare with modifiedAt). A row changes whenever a product gains or loses its value, because its productCount changes; on a list built from the products it also changes whenever a product carrying the value changes. A store whose list keeps no modification time answers 422 modified_since_unsupported.","in":"query","name":"modifiedSince","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TagListResponse"}}},"description":"One live page of the tags the store's products carry, each with its product count, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number of 1 or more, cursor is not one a previous page issued, or modifiedSince is not an RFC3339 timestamp (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and a store-wide list cannot be narrowed to it (rejected before billing). modified_since_unsupported: the tag list keeps no modification time; list without modifiedSince. tags_unsupported: the store's POS database keeps no tag list and its products carry no tags to build one from, or more than 10,000 distinct tag lists. agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the tag list (code store_error): the agent answered an error, or the relay build predates this operation (an agent that predates it is 422 agent_update_required). The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's product tags live","tags":["reference","catalog","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"catalog.reference.read"}},"x-compudime-capability-id":"catalog-feed","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"reference","x-compudime-field-catalog":{"fields":["name","productCount","modifiedAt"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"catalog.tags.default","standardFields":["name","productCount","modifiedAt"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"catalog.reference.read","x-compudime-token-cost":1}},"/v1/tenders":{"get":{"operationId":"tenders.list","parameters":[{"description":"Comma-separated tenders fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenderListResponse"}}},"description":"The register's tender (payment type) list, as configured in the POS."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the tender list (code store_error)."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS did not answer inside the tender list ceiling (code store_timeout)."}},"security":[{"bearerAuth":[]}],"summary":"List the register's tender types","tags":["tenders"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"customers.read.all"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"customers.read.all"}},"x-compudime-capability-id":"customer-access","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"tenders","x-compudime-field-catalog":{"fields":["code","name","position","group"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"tenders.default","standardFields":["code","name","position","group"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"customers.read.all","x-compudime-token-cost":1}},"/v1/tickets":{"get":{"operationId":"tickets.list","parameters":[{"description":"Comma-separated register tickets fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"First business day to read (YYYY-MM-DD, the store's calendar), inclusive. Required. A ticket's business day is the day the POS assigned it (a ticket rung after midnight, before the register's close time, belongs to the day before), else its date.","in":"query","name":"from","required":true,"schema":{"format":"date","type":"string"}},{"description":"Last business day to read (YYYY-MM-DD), inclusive. Required; not before from. Any span. The store reads tickets 31 days at a time, so a longer range is read in 31-day stretches counted from from, in date order (the tickets of each stretch in ticket id order), one after another until the answer holds limit tickets or the range ends (there is no time limit on reading, PAPI-PAGE-007); a page can still end early while nextCursor is set, when this API or the store is busy with other long answers. Keep following nextCursor until it is empty.","in":"query","name":"to","required":true,"schema":{"format":"date","type":"string"}},{"description":"Only the tickets of this register: its code as the rows show it (register), 1-2 letters or digits. A one-digit code and the same digit with a leading 0 name the same register (1 and 01), as the register itself treats them.","in":"query","name":"register","required":false,"schema":{"pattern":"^[A-Za-z0-9]{1,2}$","type":"string"}},{"description":"Ticket types to read: a comma-separated list of the TicketHD type letters S, O, V, T, R, G, H and A (either case), each at most once. Omitted: the sale types S and O. Only the two sale types are read unless type names others: S (a completed register sale) and O (a direct account charge or payment, which normally carries a sale of 0). The other types are not sales and must never be summed as revenue: V a voided sale (its sale total is still filled in), T calculate-only or a transfer whose value already landed on another ticket (it would double-count), R a transfer ticket not yet paid, G training mode, H a held sale and A a sale still being rung. Compare with type and sale on a row.","in":"query","name":"type","required":false,"schema":{"pattern":"^[SOVTRGHAsovtrgha](,[SOVTRGHAsovtrgha]){0,7}$","type":"string"}},{"description":"How many tickets to return: any whole number of 1 or more; default 100 (one page). The store is read 200 at a time, so a larger limit is read from the store in several reads, one after another, and answered at once. One answer carries at most 10,000 (a safeguard on the size of one answer, not a limit on the listing); a larger limit ends with nextCursor. There is no time limit on reading: an answer that needs several reads keeps reading until it holds limit rows (at most 10,000) or the listing ends. While it reads, the response is already open: its body starts with spaces (legal JSON whitespace, sent every few seconds so no proxy closes an idle connection), and X-Credits-Charged and X-Credits-Remaining are not response headers but HTTP trailers, which reach HTTP/2 clients (on api.compudime.com and compudime-public-api.fly.dev alike) and are dropped over HTTP/1.1. The billing block in the body always says what the call cost (totalCredits per unit times quantity); /v1/usage/current gives the balance. When this API or the store is busy with other long answers, an answer may end after its first read with nextCursor instead. A page can hold fewer rows than limit while nextCursor is set: keep following nextCursor until it is empty.","in":"query","name":"limit","required":false,"schema":{"default":100,"minimum":1,"type":"integer"}},{"description":"nextCursor from the previous page, verbatim, with the same from, to, register and type: a cursor continues only the listing it came from, and any other is a free 400. Omit for the first page; an empty nextCursor means the last page.","in":"query","name":"cursor","required":false,"schema":{"maxLength":1024,"pattern":"^[A-Za-z0-9_-]{1,1024}$","type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketListResponse"}}},"description":"One live page of the store's register ticket headers of a business-day range in a stable order, with the cursor for the next page."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"from or to is missing or not a YYYY-MM-DD day, to is before from, register or type is not of the documented shape, limit is not a whole number of 1 or more, cursor is not one a previous page of this very listing issued (the same from, to, register and type), or modifiedSince was sent (the POS keeps no ticket modification time an incremental read could trust) (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key is not a sales-data key with the sales.read scope (rejected before billing). store_feature_not_enabled: the key is entitled, but the store has not turned on per-item data for developers on its own POS agent (the same store switch as sales movement and the invoice reads); nothing changes until the store enables it. The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a register ticket or a register log (rejected before billing). agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. tickets_unsupported: the store's POS database has no register ticket tables with the columns these reads need. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the ticket list (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"List the store's register tickets live","tags":["sales","tickets","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"tickets","x-compudime-field-catalog":{"fields":["ticketId","register","type","sale","businessDay","date","time","createdAt","finishedAt","logNumber","customerId","anonymousCustomer","payType","totals","ticketDiscountPercent","customerDiscountPercent","taxExempt","taxRate1","taxRate2","priceLevel","paperBagCount","upChargePercent"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"tickets.default","standardFields":["ticketId","register","type","sale","businessDay","date","time","createdAt","finishedAt","logNumber","customerId","anonymousCustomer","payType","totals","ticketDiscountPercent","customerDiscountPercent","taxExempt","taxRate1","taxRate2","priceLevel","paperBagCount","upChargePercent"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"page"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/tickets/{ticketId}":{"get":{"operationId":"tickets.get","parameters":[{"description":"The POS ticket id (ticketId on any ticket row): 1-13 letters or digits. Anything else is a free 400 before billing.","in":"path","name":"ticketId","required":true,"schema":{"pattern":"^[A-Za-z0-9]{1,13}$","type":"string"}},{"description":"Ticket types to read: a comma-separated list of the TicketHD type letters S, O, V, T, R, G, H and A (either case), each at most once. Omitted: the sale types S and O. Only the two sale types are read unless type names others: S (a completed register sale) and O (a direct account charge or payment, which normally carries a sale of 0). The other types are not sales and must never be summed as revenue: V a voided sale (its sale total is still filled in), T calculate-only or a transfer whose value already landed on another ticket (it would double-count), R a transfer ticket not yet paid, G training mode, H a held sale and A a sale still being rung. Compare with type and sale on a row.","in":"query","name":"type","required":false,"schema":{"pattern":"^[SOVTRGHAsovtrgha](,[SOVTRGHAsovtrgha]){0,7}$","type":"string"}},{"description":"Comma-separated register ticket detail fields to include (see x-compudime-field-catalog), or * for every field the key may see. Omitted: a flat-priced endpoint returns every field; once IT prices the endpoint by field count (includedFields in x-compudime-pricing), an omitted fields returns the standard set at the base price and each field beyond the included count adds extraFieldCost. An unknown or denied field is a free 400 field_not_allowed.","in":"query","name":"fields","required":false,"schema":{"type":"string"}},{"description":"When true, returns EstimateResponse instead of the normal body and never reserves credits: the request is authenticated, authorized and field-resolved exactly like a real call, then priced by billing (base cost plus extra-field credits for the resolved fields) and returned without dispatching to the store. Free of charge.","in":"query","name":"estimate","required":false,"schema":{"default":false,"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketResponse"}}},"description":"The live register ticket with that id, with its lines and its tenders."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"ticketId is not 1-13 letters or digits, or type is not of the documented shape (code bad_request); or a requested field is not allowed (code field_not_allowed). Rejected before billing."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The request was blocked by billing policy: no_api_plan (no plan funds this meter), billing_card_missing, billing_card_failed, usage_exhausted, overage_cap_reached, subscription_paused, sandbox_exhausted, or billing_blocked. A key the store pays for under its approval gets grant_cap_exceeded (the store's monthly limit for your calls) or payer_billing_blocked (the store cannot be charged right now; ask the store owner) instead: what is wrong with the store's billing is not shown to it."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"capability_not_enabled: the API key is not a sales-data key with the sales.read scope (rejected before billing). store_feature_not_enabled: the key is entitled, but the store has not turned on per-item data for developers on its own POS agent (the same store switch as sales movement and the invoice reads); nothing changes until the store enables it. The reservation is released, nothing is charged."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store has no ticket with that id among the requested types (code ticket_not_found; without type, only the sale types S and O are read). The reservation is released, nothing is charged."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"scope_not_applicable: the API key carries a row scope, and no row scope can be applied to a register ticket or a register log (rejected before billing). agent_update_required: the store's CompuDime agent is older than these reads; the store must update it. tickets_unsupported: the store's POS database has no register ticket tables with the columns these reads need. The reservation is released, nothing is charged."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Billed endpoints are also subject to the store plan's per-minute ceiling, which answers the same problem code. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"502":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS could not complete the ticket read (code store_error): the agent answered an error, the store has not enabled per-item data for developers, or the agent or relay build predates this operation. The reservation is released."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store's POS agent is offline (code store_offline), or a Public API dependency is unavailable. The reservation is released. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}},"504":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The store did not answer inside the read ceiling (code store_timeout). The reservation is released."}},"security":[{"bearerAuth":[]}],"summary":"Get a register ticket live with its lines and tenders","tags":["sales","tickets","live"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"sales.read"}},"x-compudime-capability-id":"sales-data","x-compudime-estimate":{"description":"With estimate=true the 200 body is EstimateResponse (a priced quote for exactly this request), not the schema documented under responses.200; nothing is reserved or dispatched.","parameter":"estimate","schema":{"$ref":"#/components/schemas/EstimateResponse"}},"x-compudime-family":"tickets","x-compudime-field-catalog":{"fields":["ticketId","register","type","sale","businessDay","date","time","createdAt","finishedAt","logNumber","customerId","anonymousCustomer","payType","totals","ticketDiscountPercent","customerDiscountPercent","taxExempt","taxRate1","taxRate2","priceLevel","paperBagCount","upChargePercent","lines","linesTruncated","tenders","tendersTruncated"],"note":"fields lists every name this endpoint can return (sensitive names are never in it); standardFields is what an omitted fields parameter returns under the published pricing: the whole catalog while the endpoint is flat, the first includedFields of it once IT prices the endpoint by field count. A key pinned to a field policy sees only its policy's fields and its policy's standard set.","pricingRule":"flat","resource":"tickets.detail","standardFields":["ticketId","register","type","sale","businessDay","date","time","createdAt","finishedAt","logNumber","customerId","anonymousCustomer","payType","totals","ticketDiscountPercent","customerDiscountPercent","taxExempt","taxRate1","taxRate2","priceLevel","paperBagCount","upChargePercent","lines","linesTruncated","tenders","tendersTruncated"]},"x-compudime-pricing":{"baseCost":1,"meter":"api","note":"default price; the effective price depends on the store's plan and any overrides (billing.priceSource on a billed response and priceSource on an estimate name the layer that priced the call: default, plan, subscription, or house), and a store without a plan on this meter receives 402 no_api_plan. Field selection: with fields omitted, a flat-priced endpoint (no includedFields here) returns every field of its catalog; once the endpoint is priced by field count (includedFields \u003e 0) an omitted fields returns the standard set at the base price and each field beyond includedFields adds extraFieldCost. fields=* and explicit lists work on every read endpoint (see x-compudime-field-catalog). Unit: the price is per request by default (unit request, or order); CompuDime may price a paged list endpoint per row instead (unit row), in which case the price here (base plus extra fields) is charged for each row the call returns, or per page (unit page), in which case it is charged for each page of 100 rows the call returns, rounded up (1 to 100 rows are one page, 101 are two): the call reserves its page bound (the effective limit, or the day count of a daily range), settles down to the rows returned, and an empty page costs nothing. A billed response then says unit row or page and quantity (the rows, or the pages, bought) in its billing block, X-Credits-Charged is the total, and estimate=true answers the unit, quantity (the page bound in rows, or the pages it fills) and totalCredits (the most the call can cost)","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"sales.read","x-compudime-token-cost":1}},"/v1/usage/current":{"get":{"description":"The store's month so far on the API meter: its plan, card state, overage and its cap, the credits used and included, and the calls per endpoint. Only the store's own keys read it. A key your organization holds for a store (a developer's key under the owner's approval, for instance) is billed to your organization and is not shown the store's billing: it gets 403 usage_not_available_for_key, and your organization's usage is at https://account.compudime.com/usage. Free.","operationId":"platform.usage.current","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageSummary"}}},"description":"The store's usage summary for the month, for the store's own keys."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint; or usage_not_available_for_key: the key is held by your organization, not the store, so it cannot read the store's plan, card or credits (your organization's usage is at https://account.compudime.com/usage)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get current API usage","tags":["platform","usage"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.usage.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"platform.usage.read"}},"x-compudime-family":"platform","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"platform.usage.read","x-compudime-token-cost":0}},"/v1/webhooks":{"get":{"description":"Your integration's receivers for the calling key's mode, oldest first, each with its latest delivery. Never a secret: secretPrefix is its first characters, enough to tell secrets apart. Free, and needs only a valid key (a key without order intake has none). Receivers belong to the calling key's integration and mode. A live key's receivers get the order events they subscribe to; a test key's receivers get only the test events you send them, because a test key's orders are simulated and never send a webhook. A test key never sees a live receiver and a live key never sees a test one. Receivers CompuDime staff registered for your integration are live receivers.","operationId":"webhooks.list","responses":{"200":{"content":{"application/json":{"example":{"requestId":"req_0123456789abcdef","webhooks":[{"id":"7b0c9a1e-3f52-4c1d-9a7e-2d4f6b8c0e13","url":"https://hooks.example.com/compudime/orders","events":["order.dispatched","order.parked"],"active":true,"mode":"live","secretPrefix":"whsec_3f9a1c","createdAt":"2026-10-13T15:00:00Z","updatedAt":"2026-10-13T15:00:00Z","lastDelivery":{"id":"c2e8f4a0-6b1d-4e3f-8a9c-0d2e4f6a8b1c","event":"webhook.test","state":"delivered","attempts":1,"lastStatus":204,"createdAt":"2026-10-13T15:01:00Z","updatedAt":"2026-10-13T15:01:21Z","deliveredAt":"2026-10-13T15:01:21Z"}}],"limit":5},"schema":{"$ref":"#/components/schemas/WebhookListResponse"}}},"description":"Your receivers for this key mode."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List your webhook receivers","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"}},"x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"webhooks.read","x-compudime-token-cost":0},"post":{"description":"Registers an HTTPS receiver for the order events of your integration and answers 201 with it and its signing secret. This signing secret is shown once, in this answer, and never again: store it now, like a password. If you lose it, rotate it (POST /v1/webhooks/{webhookId}/rotate-secret). url must start with https://, reach a public address (private, loopback, link-local and other reserved addresses are refused as typed, and again when CompuDime connects), carry no user name or password, and be at most 2048 characters long. events names at least one order event (see the top-level webhooks); webhook.test is not one, every receiver gets the test events you send it. Your integration may keep at most 5 receivers per key mode (409 webhook_limit_reached), and a URL it already has is 409 webhook_exists naming that receiver, so retrying after a lost answer never registers twice. Needs a key with the order-intake capability. Free. Receivers belong to the calling key's integration and mode. A live key's receivers get the order events they subscribe to; a test key's receivers get only the test events you send them, because a test key's orders are simulated and never send a webhook. A test key never sees a live receiver and a live key never sees a test one. Receivers CompuDime staff registered for your integration are live receivers.","operationId":"webhooks.create","requestBody":{"content":{"application/json":{"example":{"url":"https://hooks.example.com/compudime/orders","events":["order.dispatched","order.parked"]},"schema":{"$ref":"#/components/schemas/WebhookCreateRequest"}}},"required":true},"responses":{"201":{"content":{"application/json":{"example":{"requestId":"req_0123456789abcdef","webhook":{"id":"7b0c9a1e-3f52-4c1d-9a7e-2d4f6b8c0e13","url":"https://hooks.example.com/compudime/orders","events":["order.dispatched","order.parked"],"active":true,"mode":"live","secretPrefix":"whsec_3f9a1c","createdAt":"2026-10-13T15:00:00Z","updatedAt":"2026-10-13T15:00:00Z"},"secret":"whsec_3f9a1c\u003c58 more hex digits\u003e","secretNote":"This signing secret is shown once, in this answer, and never again: store it now, like a password. If you lose it, rotate it (POST /v1/webhooks/{webhookId}/rotate-secret)."},"schema":{"$ref":"#/components/schemas/WebhookSecretResponse"}}},"description":"The receiver is registered; secret is shown in this answer only."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The body is not a JSON object with url and events, the url breaks a rule (url must start with https://, reach a public address (private, loopback, link-local and other reserved addresses are refused as typed, and again when CompuDime connects), carry no user name or password, and be at most 2048 characters long.), or events is empty or names an event that does not exist (code bad_request)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key does not carry the order-intake capability, or the store has not turned it on (code capability_not_enabled)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"webhook_exists: your key already has a receiver with this url; the detail names it. webhook_limit_reached: your integration already keeps 5 receivers for this key mode."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Register a webhook receiver","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"}},"x-compudime-capability-id":"order-intake","x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.webhooks","x-compudime-token-cost":0}},"/v1/webhooks/{webhookId}":{"delete":{"description":"Removes one of your receivers: nothing is sent to it again, including deliveries still waiting for a retry, and it no longer appears in your list. The store owner still sees it in the console, marked removed. Free, and needs only a valid key.","operationId":"webhooks.delete","parameters":[{"description":"The receiver's id (id in the answer of POST /v1/webhooks or GET /v1/webhooks). An id your key has no receiver under is 404 webhook_not_found.","in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeletedResponse"}}},"description":"The receiver is removed."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Your key has no receiver with this id: it never existed, belongs to another integration or to a key of the other mode, or you removed it (code webhook_not_found)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Remove a webhook receiver","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.write"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.write"}},"x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"webhooks.write","x-compudime-token-cost":0},"get":{"description":"One of your receivers with its latest delivery; never its secret. A receiver of another integration, of the other key mode, or one you removed is 404 webhook_not_found. Free.","operationId":"webhooks.get","parameters":[{"description":"The receiver's id (id in the answer of POST /v1/webhooks or GET /v1/webhooks). An id your key has no receiver under is 404 webhook_not_found.","in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookResponse"}}},"description":"The receiver."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Your key has no receiver with this id: it never existed, belongs to another integration or to a key of the other mode, or you removed it (code webhook_not_found)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Get a webhook receiver","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"}},"x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"webhooks.read","x-compudime-token-cost":0}},"/v1/webhooks/{webhookId}/deliveries":{"get":{"description":"The receiver's newest deliveries, order events and test events, newest first: state (pending, failed, delivered, dead), attempts, the last HTTP status and error. Use it to see why your receiver is not getting events. Free.","operationId":"webhooks.deliveries.list","parameters":[{"description":"The receiver's id (id in the answer of POST /v1/webhooks or GET /v1/webhooks). An id your key has no receiver under is 404 webhook_not_found.","in":"path","name":"webhookId","required":true,"schema":{"type":"string"}},{"description":"How many deliveries to return, newest first: 1 to 100; omitted, 20. Anything else is 400 bad_request.","in":"query","name":"limit","required":false,"schema":{"maximum":100,"minimum":1,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryListResponse"}}},"description":"The receiver's newest deliveries."},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"limit is not a whole number from 1 to 100 (code bad_request)."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key is not enabled for this endpoint."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Your key has no receiver with this id: it never existed, belongs to another integration or to a key of the other mode, or you removed it (code webhook_not_found)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"List a receiver's recent deliveries","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"webhooks.read"}},"x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"webhooks.read","x-compudime-token-cost":0}},"/v1/webhooks/{webhookId}/rotate-secret":{"post":{"description":"Replaces the receiver's signing secret and answers the new one. This signing secret is shown once, in this answer, and never again: store it now, like a password. If you lose it, rotate it (POST /v1/webhooks/{webhookId}/rotate-secret). The old secret stops verifying from the next delivery attempt, retries of earlier events included, so switch your receiver to the new secret at once. Needs a key with the order-intake capability. Free.","operationId":"webhooks.rotate_secret","parameters":[{"description":"The receiver's id (id in the answer of POST /v1/webhooks or GET /v1/webhooks). An id your key has no receiver under is 404 webhook_not_found.","in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSecretResponse"}}},"description":"The secret is replaced; the new secret is shown in this answer only."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key does not carry the order-intake capability, or the store has not turned it on (code capability_not_enabled)."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Your key has no receiver with this id: it never existed, belongs to another integration or to a key of the other mode, or you removed it (code webhook_not_found)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Rotate a receiver's signing secret","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"}},"x-compudime-capability-id":"order-intake","x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.webhooks","x-compudime-token-cost":0}},"/v1/webhooks/{webhookId}/test":{"post":{"description":"Queues one signed webhook.test event to the receiver and answers 202 with its delivery. CompuDime posts it within about a minute, through the same path, headers and signature as the order events, and retries a failure on the same schedule; follow it on GET /v1/webhooks/{webhookId}/deliveries. Use it to check your signature verification before the first order. At most 10 test events per receiver in an hour (429 rate_limited with Retry-After). A disabled receiver is 409 webhook_inactive. Works with test keys too: it is the only event a test key's receiver gets. Needs a key with the order-intake capability. Free.","operationId":"webhooks.test","parameters":[{"description":"The receiver's id (id in the answer of POST /v1/webhooks or GET /v1/webhooks). An id your key has no receiver under is 404 webhook_not_found.","in":"path","name":"webhookId","required":true,"schema":{"type":"string"}}],"responses":{"202":{"content":{"application/json":{"example":{"requestId":"req_0123456789abcdef","delivery":{"id":"c2e8f4a0-6b1d-4e3f-8a9c-0d2e4f6a8b1c","event":"webhook.test","state":"pending","attempts":0,"nextAttemptAt":"2026-10-13T15:01:00Z","createdAt":"2026-10-13T15:01:00Z","updatedAt":"2026-10-13T15:01:00Z"},"note":"Queued. CompuDime posts it within about a minute; follow it on GET /v1/webhooks/{webhookId}/deliveries."},"schema":{"$ref":"#/components/schemas/WebhookTestQueuedResponse"}}},"description":"The test event is queued for delivery."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Public API key is missing, invalid, or revoked."},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API key does not carry the order-intake capability, or the store has not turned it on (code capability_not_enabled)."},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Your key has no receiver with this id: it never existed, belongs to another integration or to a key of the other mode, or you removed it (code webhook_not_found)."},"405":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The requested method is not allowed for this endpoint."},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The receiver is disabled (code webhook_inactive): the store owner or CompuDime turned it off, so nothing would be sent to it."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"Too many requests from this API key (code rate_limited). Each key has its own request budget at the API edge, refilled continuously; it covers every authenticated endpoint, including the free ones, and is checked before anything is billed or sent to the store. Wait at least Retry-After seconds before the next request with this key, then resume; if 429 answers again, back off exponentially (double the wait each time, up to a minute or so) and add random jitter so parallel workers do not retry in step. A 429 is never charged and reserves nothing. Also answered when 10 test events were sent to this receiver in the last hour; Retry-After then says when the next one may be sent.","headers":{"Retry-After":{"description":"Whole seconds to wait before retrying with this key: the time until the key's next request token at the edge (never less than 1), or 60 when the store plan's per-minute ceiling refused the call.","required":true,"schema":{"minimum":1,"type":"integer"}}}},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"The API edge encountered an internal error."},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Problem"}}},"description":"A required Public API dependency is temporarily unavailable. Also answered, with code endpoint_disabled, while CompuDime has temporarily switched the endpoint off: the whole API, the endpoint's family (x-compudime-family) or this endpoint alone; the detail says which and why. It is checked before anything is validated, reserved or sent to the store, so it is never charged; it is retryable and carries Retry-After.","headers":{"Retry-After":{"description":"Sent with code endpoint_disabled: whole seconds to wait before asking again. A switch has no scheduled end, so this is a polling interval (60), not a promise.","schema":{"minimum":1,"type":"integer"}}}}},"security":[{"bearerAuth":[]}],"summary":"Send a test event to a receiver","tags":["webhooks"],"x-compudime-access-level":{"all":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"},"narrowsRows":false,"own":{"effect":"The level does not change this operation: own and all return the same data.","scope":"orders.webhooks"}},"x-compudime-capability-id":"order-intake","x-compudime-family":"webhooks","x-compudime-pricing":{"baseCost":0,"meter":"api","pricingVersion":"2026-10-09.2","unit":"request"},"x-compudime-scope":"orders.webhooks","x-compudime-token-cost":0}}},"security":[{"bearerAuth":[]}],"servers":[{"description":"CompuDime Public API","url":"https://api.compudime.com"},{"description":"The same API at its earlier address; integrations that already call it keep working there.","url":"https://compudime-public-api.fly.dev"}],"webhooks":{"order.canceled":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.canceled. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"The store deleted the order from its POS, which is how the POS cancels an order: data.fulfillment.canceledAt. Final. Sent once per order and receiver, when the order status sync first sees the step (it reads the store every few minutes, so a step can be announced minutes after it happened, and two steps can arrive together or out of order: go by data.fulfillment.state). data.fulfillment is the whole fulfillment object as the order reads show it; data.invoice links the POS invoice. Only for orders at stores whose agent reads order status for the platform.","tags":["orders","webhooks"]}},"order.completed":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.completed. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"An order that is not a delivery was rung up at the store's register (the customer checked out): data.fulfillment.completedAt. Final. Sent once per order and receiver, when the order status sync first sees the step (it reads the store every few minutes, so a step can be announced minutes after it happened, and two steps can arrive together or out of order: go by data.fulfillment.state). data.fulfillment is the whole fulfillment object as the order reads show it; data.invoice links the POS invoice. Only for orders at stores whose agent reads order status for the platform.","tags":["orders","webhooks"]}},"order.delivered":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.delivered. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"The store recorded the delivery as done: data.fulfillment.deliveredAt. Final. Sent once per order and receiver, when the order status sync first sees the step (it reads the store every few minutes, so a step can be announced minutes after it happened, and two steps can arrive together or out of order: go by data.fulfillment.state). data.fulfillment is the whole fulfillment object as the order reads show it; data.invoice links the POS invoice. Only for orders at stores whose agent reads order status for the platform.","tags":["orders","webhooks"]}},"order.dispatched":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.dispatched. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"The order landed in the store's POS: data.invoice links the POS invoice (by feed identity), and data.posOrderRef is the store's own reference, not an invoice number. Treat it as final for dispatch; the fulfillment events (order.picked and the ones after it) may follow.","tags":["orders","webhooks"]}},"order.out_for_delivery":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.out_for_delivery. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"A driver took the order: data.fulfillment.outForDeliveryAt, and data.fulfillment.eta when the store recorded one. Sent once per order and receiver, when the order status sync first sees the step (it reads the store every few minutes, so a step can be announced minutes after it happened, and two steps can arrive together or out of order: go by data.fulfillment.state). data.fulfillment is the whole fulfillment object as the order reads show it; data.invoice links the POS invoice. Only for orders at stores whose agent reads order status for the platform.","tags":["orders","webhooks"]}},"order.parked":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.parked. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"Dispatch stopped (a permanent POS rejection, the retry bound, or the store's operator parked the order): data.dispatchError says why. The owner can retry it from the console, after which order.dispatched may follow.","tags":["orders","webhooks"]}},"order.picked":{"post":{"description":"CompuDime POSTs this body to each active live receiver registered for your order-intake integration (by you through POST /v1/webhooks, or by CompuDime) and subscribed to order.picked. Verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) before trusting it, and deduplicate on id: retries and redeliveries carry the same id. Deliveries are not billed. A test key's orders are simulated and never send a webhook.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderWebhookEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"The store finished picking the order: data.fulfillment.pickedAt. Sent once per order and receiver, when the order status sync first sees the step (it reads the store every few minutes, so a step can be announced minutes after it happened, and two steps can arrive together or out of order: go by data.fulfillment.state). data.fulfillment is the whole fulfillment object as the order reads show it; data.invoice links the POS invoice. Only for orders at stores whose agent reads order status for the platform.","tags":["orders","webhooks"]}},"webhook.test":{"post":{"description":"CompuDime POSTs this body to the one receiver you named, signed exactly like the order events: verify X-CompuDime-Signature (sha256=\u003chex HMAC-SHA256 of the raw body under the receiver's secret\u003e) and answer 2xx. Every receiver gets the test events sent to it, whatever events it subscribes to. A test key's orders are simulated and never send a webhook, so the test event is the one a test key's receiver gets. Deliveries are not billed.","parameters":[{"description":"The event name, the same as type in the body.","in":"header","name":"X-CompuDime-Event","required":true,"schema":{"type":"string"}},{"description":"The delivery id, the same as id in the body.","in":"header","name":"X-CompuDime-Delivery","required":true,"schema":{"type":"string"}},{"description":"When this attempt was sent (RFC 3339, UTC).","in":"header","name":"X-CompuDime-Timestamp","required":true,"schema":{"type":"string"}},{"description":"sha256= followed by the hex HMAC-SHA256 of the raw request body under the receiver's signing secret.","in":"header","name":"X-CompuDime-Signature","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookTestEvent"}}},"required":true},"responses":{"2XX":{"description":"Any 2xx within 10 seconds acknowledges the delivery; the body is ignored. Anything else, a timeout or a redirect is a failed attempt and is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 12 hours."}},"security":[],"summary":"Sent only when you ask: POST /v1/webhooks/{webhookId}/test. It is about no order; use it to check that your receiver verifies the signature and answers 2xx.","tags":["webhooks"]}}},"x-compudime-billing-plans":[{"id":"starter","displayName":"API Starter","monthlyPrice":500,"includedCredits":1000,"overageUnitPrice":0.7,"rateLimitPerMin":30,"syncCadence":"Hourly","sandboxCredits":500,"active":true},{"id":"growth","displayName":"API Growth","monthlyPrice":800,"includedCredits":1500,"overageUnitPrice":0.55,"rateLimitPerMin":60,"syncCadence":"30 minutes","sandboxCredits":500,"active":true},{"id":"scale","displayName":"API Scale","monthlyPrice":1500,"includedCredits":3500,"overageUnitPrice":0.4,"rateLimitPerMin":120,"syncCadence":"15 minutes","sandboxCredits":500,"active":true},{"id":"pulse","displayName":"Store Pulse","monthlyPrice":100,"includedCredits":50000,"overageUnitPrice":0.005,"rateLimitPerMin":120,"syncCadence":"5 minutes","sandboxCredits":500,"active":true,"meter":"pulse"}],"x-compudime-billing-plans-note":"seed defaults; live values are database-backed","x-compudime-capability-bundles":[{"id":"catalog-feed","displayName":"Catalog Feed","generallyOpen":true,"endpointFamilies":["product list","product lookup","snapshot metadata","promotions (live)","categories, brands and tags (live)","reasons and store profile (live)"],"scopes":["catalog.products.read","catalog.snapshots.read","catalog.reference.read"]},{"id":"order-intake","displayName":"Order Intake","generallyOpen":false,"lockedReason":"Requires CompuDime enablement.","endpointFamilies":["order post","order status (by order id or external id)","order webhooks (dispatched, parked)"],"scopes":["orders.write","orders.read","orders.webhooks"]},{"id":"order-dispatch","displayName":"Order POS Dispatch","generallyOpen":false,"lockedReason":"Requires CompuDime enablement and a store-machine opt-in; delivers queued orders into the POS.","endpointFamilies":["order POS delivery"],"scopes":["orders.dispatch"]},{"id":"sales-data","displayName":"Sales Movement Data","generallyOpen":false,"lockedReason":"Requires CompuDime enablement; per-item sales movement, brand-scopeable.","endpointFamilies":["sales movement (register + delivery)","inventory on-hand (live)","invoices (live)","delivery routes (live)","register tickets (live)","register Z reports (live)"],"scopes":["sales.read"]},{"id":"customer-access","displayName":"Customer Access","generallyOpen":false,"lockedReason":"Requires CompuDime enablement and a store-machine opt-in; reads customer profiles from the POS.","endpointFamilies":["customer phone lookup","customer list","customer by POS id","own or all customers (integration access level)"],"scopes":["customers.read.self","customers.read.all"]},{"id":"sales-bi","displayName":"Sales And BI","generallyOpen":false,"lockedReason":"Requires CompuDime enablement.","endpointFamilies":["future invoices","future sales feeds"],"scopes":["invoices.read","sales.read"]},{"id":"giftcard-payments","displayName":"Gift Cards And Payments","generallyOpen":false,"lockedReason":"Requires CompuDime enablement.","endpointFamilies":["future gift-card endpoints","future payment endpoints"],"scopes":["giftcards.read","giftcards.write","payments.read","payments.write"]},{"id":"purchasing-data","displayName":"Purchasing Data","generallyOpen":false,"lockedReason":"Requires CompuDime enablement and a store-machine opt-in; exposes what the store pays its vendors (purchase orders, receiving, case costs).","endpointFamilies":["purchase orders (live)","receiving documents (live)"],"scopes":["purchasing.read"]},{"id":"accounting-data","displayName":"Accounting Data","generallyOpen":false,"lockedReason":"Requires CompuDime enablement; exposes the register's close-out totals with cost of goods sold, as summaries and as journal entries through the store's account mapping.","endpointFamilies":["register-log sales summaries (live)","journal entries (live)","account mapping (live)"],"scopes":["accounting.read"]}],"x-compudime-guides":[{"description":"Get a key at account.compudime.com, make a first call, and read the answer.","title":"Quick start","url":"https://api.compudime.com/docs#quickstart"},{"description":"What each call costs in credits, how to price a call before you make it, and how the answer says what it cost.","title":"Billing and bundles","url":"https://api.compudime.com/docs/pricing"},{"description":"Every integration has an access level, own or all, set by the store owner (GET /v1/capabilities returns it as accessLevel). all reads the store's whole customer file on /v1/customers, /v1/customers/{posCustomerId} and /v1/customers/lookup under the scope customers.read.all; it is the sensitive level. own reads them under customers.read.self and returns only the customers linked to the integration: the customers its own orders (POST /v1/orders) landed on in the store's POS, matched by the customer's main phone. For a cc_ key its own orders are those sent with the same key, or with any key of the same store owner's approval. A customer outside that set is answered exactly like one the store does not have (404 customer_not_found, found:false, or absent from the page), never with a 403. The level changes nothing else: the order reads only ever show the integration's own orders, and the other reads are store data. Each operation says what the level changes in x-compudime-access-level.","title":"Access levels","url":"https://api.compudime.com/docs/authentication#access-levels"},{"description":"A key can carry a pinned data scope: a field projection (which product fields are returned) and row constraints (server-side conditions such as brand eq X, with operators eq, in, and prefix on whitelisted fields: productCode, upc, brand, department, category, active). Scoped keys page, look up, and count only within their slice on /v1/products, /v1/products/{code}, /v1/products/lookup/{code} (a live row outside the scope answers 404), /v1/catalog/snapshots/current, /v1/sales/movement and /v1/inventory/onhand (product-code scopes only; any other scope answers 422 scope_not_applicable there); there are no caller filter parameters to widen the scope. A scoped key cannot read /v1/invoices, /v1/invoices/{posInvoiceId}, /v1/invoices/external/{externalId} or /v1/delivery/routes at all (422 scope_not_applicable, never charged): an invoice and a route count cover every product of the store, so no product slice of them exists. The same holds for the purchasing reads (/v1/purchase-orders, /v1/purchase-orders/{posPurchaseOrderId}, /v1/receiving, /v1/receiving/{posReceivingId}): a document's totals and lines span every product on it. The same holds for the register ticket reads and the Z report (/v1/tickets, /v1/tickets/{ticketId}, /v1/sales/zreport). Scope changes create new audited policy versions in the owner console.","title":"Scoped API keys","url":"https://api.compudime.com/docs/authentication#scoped-keys"},{"description":"Every list is paged with limit, cursor and nextCursor; how long answers arrive; syncing only what changed.","title":"Paging and cursors","url":"https://api.compudime.com/docs/paging"},{"description":"Order events sent to your receiver, their signature, and retries; registering, testing and removing your own receivers.","title":"Webhooks","url":"https://api.compudime.com/docs/webhooks"},{"description":"The per-key request budget, 429 and Retry-After.","title":"Rate limits","url":"https://api.compudime.com/docs/rate-limits"},{"description":"The problem body and every problem code, one anchor per code.","title":"Errors","url":"https://api.compudime.com/docs/errors"},{"description":"What changed in the API, newest first, one entry per day. info.version is the date of the newest entry.","title":"Changelog","url":"https://api.compudime.com/docs/changelog"},{"description":"Which changes ship any day, how a breaking change is announced in the changelog the day it ships, and the Deprecation and Sunset headers.","title":"Versioning and deprecation","url":"https://api.compudime.com/docs/versioning"},{"description":"The demo store, CompuDime Demo Market: invented products, customers, stock, sales and invoices for test keys, never billed. What it answers, and how to get a key.","title":"Sandbox","url":"https://api.compudime.com/docs/sandbox"}],"x-compudime-pricing-version":"2026-10-09.2"}
