Changelog

What changed in the Glance API, newest first. Each change links to the reference that shows how to use it.

Every entry has its own address — open it from the entry's date to link straight to that change. Entries marked Changed can affect an existing integration; when they do, the entry says what to do.

  1. Setting for the ILS estimate on foreign-currency purchases

    PUT /settings accepts showIlsEstimate. When it is on, Glance shows an estimated ILS amount at the market rate next to purchase documents in a foreign currency.

    • Defaults to true. It only changes what the screens show; no stored amount or rate changes.
    • GET /settings returns it with the rest of the company row.
  2. Linked ids must belong to the same company

    An optional id in a create or edit body that points at another company's record is now ignored instead of stored. The request still succeeds, without that link.

    • This covers numeric relatedDocuments[].id on document creation, a product's fileId and vendorIds, a warehouse's or contact's addressId, and a client's or vendor's address and logo.
    • Where the link is the point of the call, the answer is a 404: PUT /retainers/:id with another company's clientId returns CLIENT_NOT_FOUND, as create already did, and attaching a file to another company's client, product or document is refused.
    • Reads return linked rows only when they belong to the company.
    What to do: Nothing for an integration that only sends ids it read from the same company. If a link you expect is missing, check that the id comes from the company the API key belongs to.
  3. Block new documents for clients with overdue invoices

    A company can set overdueBlockDays. POST /documents/create/{type} then refuses a sales document that adds to the debt of a client with an open invoice more than that many days past its due date, with 409 CLIENT_OVERDUE_DEBT.

    • error.details carries overdueBlockDays, overdueAmount, overdueDocuments, maxDaysOverdue and canOverride.
    • The check runs before a document number is used. A document that adds nothing to the debt — a quote, a fully paid invoice-receipt — is never refused, and debt without a payBy is never overdue.
    • An owner-level key can resend with creditLimitOverride: true, the same flag the credit-limit block uses.
    • PUT /settings takes overdueBlockDays: 0 to 365, or null (the default — no block). GET /clients/entity/:entityId adds overdueBlocked, overdueAmount and maxDaysOverdue while the block is on.
    What to do: Nothing unless the company sets overdueBlockDays. If it might, handle 409 CLIENT_OVERDUE_DEBT on document creation the same way as CREDIT_LIMIT_EXCEEDED.
  4. Two new document origins: PORTAL and ONLINE_ORDER

    Documents from orders a client places in the customer portal have origin PORTAL, and documents from online-shop orders have origin ONLINE_ORDER. Both used to be recorded as POS.

    • GET /documents accepts both values in the origin filter, and GET /reports/documents-by-origin reports them as their own channels.
    • Documents issued before the change keep the origin they were issued with.
    What to do: If you filter or group documents by origin=POS to find online-shop orders, add ONLINE_ORDER (and PORTAL for portal orders).
  5. Walk-in buyers on documents

    A counter sale or payment link that goes on the company's walk-in card now returns the buyer's own name, tax id, phone and email on the document's client, with client.walkIn: true.

    • Applies to GET /documents/id/:visibleId and GET /documents. Other documents have no walkIn field.
    • Buyers who give a tax id, phone or email get their own client card instead, so their documents point at that card.
  6. Credit limits can block documents

    A company can set creditLimitPolicy to "block". POST /documents/create/{type} then refuses an order, delivery note, invoice or invoice-receipt that would take the client past its creditLimit, with 409 CREDIT_LIMIT_EXCEEDED.

    • error.details carries creditLimit, totalObligation (the client's exposure before this document), documentEffect (what the document adds), excess and canOverride.
    • The check runs before a document number is used. An invoice-receipt adds only its unpaid part, and amounts pulled from open orders or delivery notes through relatedDocuments are netted out.
    • An owner-level key gets canOverride: true and can resend the request with creditLimitOverride: true to issue anyway. The flag is not stored on the document.
    • PUT /settings takes creditLimitPolicy: "warn" (the default, same as null — nothing is blocked), "block" or "off".
    What to do: Nothing unless the company switches its policy to "block". If yours might, handle 409 CREDIT_LIMIT_EXCEEDED on document creation: show error.details, or resend with creditLimitOverride: true when the owner approves.
  7. Bills get a due date from payment terms

    A bill created without payBy now gets one from the client's payment terms, or from the company's new default terms when the client has none. A payBy you send always wins.

    • PUT /settings takes defaultPaymentTermType ("CURRENT_PLUS_DAYS" or "DAYS_ONLY") and defaultPaymentTermDays. With no terms on the client or the company, nothing changes.
    • Invoices issued by recurring billing get their due date the same way. Invoices created through the API still require payBy.
  8. Client webhooks

    Six client.* events — created, updated, deactivated, reactivated, merged and deleted — on the same webhook endpoints, with the same envelope, signature and retries.

    • data carries id (the client's visibleId), clientId, internalCode, isActive and occurredAt. No name, phone, email or address.
    • client.updated adds changedFields (field names, never values). client.merged adds mergedInto: { id, clientId }.
    • With the CRM module, a lead sends no client events. client.created is sent once, when the lead becomes a client.
    • POST /webhooks/:id/test sends a sample of each client type.
    What to do: Nothing for existing endpoints. An endpoint subscribed to "*" starts receiving client.* events — ignore types you do not handle.
  9. Merge duplicate client cards

    POST /clients/merge moves everything that points at a duplicate client — documents, balance, payments, contacts and more — to the card that stays, and retires the duplicate. GET /clients/merge/preview shows what would move first.

    • The duplicate becomes inactive with mergedIntoId set. GET /clients/id/:visibleId/merged-into returns the card it now lives in.
    • Refused with 400 TAX_ID_MISMATCH when both cards have different tax ids.
  10. One card for a client that is also a vendor

    POST /clients/id/:visibleId/vendor-role makes an existing client a vendor too, and POST /vendors/id/:visibleId/client-role does the reverse. The card keeps its visibleId.

    • GET /clients/id/:visibleId returns isVendor and vendorPayable (positive = you owe).
    • GET /vendors/id/:visibleId returns isClient, clientDebt (positive = owes you) and vendorPayable.
    • Calling either endpoint again answers alreadyHadRole: true.
  11. Find a client before creating a duplicate

    GET /clients/duplicates takes taxId, phoneNumber, email and name and returns up to 5 existing clients that share one of them, each with matchedOn.

    • Tax ids are compared by digits and phones as Israeli numbers, so 054-1234567 and +972 54 1234567 match.
  12. Client list filters, sort by debt and Excel export

    GET /clients takes groupId, customFieldId, customFieldValue, debtStatus, minDebt, ids and leads, and sortBy=debt. GET /clients/export returns the same list as an .xlsx file.

    • An invalid value in one of the new filters returns 400 INVALID_FIELD instead of being ignored.
    • Without the new parameters the list is the same as before.
  13. Set the execution status of many documents at once

    PATCH /documents/execution-status sets or clears one operational status on up to 500 documents. Ids that are not your documents come back in skipped.

  14. Why a shared document's SMS was not sent

    In POST /documents/share/:visibleId, a failed[] entry for an SMS refused by the company's SMS quota carries code: "USAGE_QUOTA_BLOCKED".

  15. Income and expense reports in shekels at each document's frozen rate

    POST /reports/income/preview returns amount, tax, totalWithTax and totals in ILS, converted at the rate frozen on each document, and adds the document's own figures next to them. The income and expenses report files sum in shekels the same way.

    • New per-document fields: documentCurrency, originalAmount, originalTax, originalTotalWithTax, exchangeRate, ilsAmountSource, cancelled, voided and notes. currency is now the currency of the returned amounts.
    • The response adds totalsCurrency: "ILS" and warnings: { missingExchangeRate, voidedExcluded }. A document with no stored rate is summed in its own currency and listed in warnings.missingExchangeRate.
    • A credit note cancelled without a counter-document is returned with voided: true and zero amounts, instead of being subtracted from the totals.
    • Files with foreign-currency documents add original-amount and exchange-rate columns; shekel-only reports keep their layout.
    What to do: If you read amount or totalWithTax from the preview as the document's own currency, switch to originalAmount and originalTotalWithTax. Shekel documents keep their amounts, except a voided credit note, which now counts as zero.
  16. What each file is attached to

    Every file in GET /files carries attachedTo — up to 3 references to the documents, expenses, clients, vendors or products it belongs to, each with a readable Hebrew label — and attachedCount, the full number.

    • Documents, clients/vendors and products include visibleId for linking; documents also include documentType and documentNumber.
  17. List only equipment expenses

    GET /expenses takes isEquipment=true to list only expenses marked as equipment (fixed assets). Without it, the list is the same as before.

  18. Job ticket webhooks, endpoint editing and test deliveries

    Eleven job_ticket.* events — one per action in a ticket's log, from created through each step to completed or cancelled — plus PATCH /webhooks/:id, POST /webhooks/:id/test and a per-endpoint station filter.

    • Events: job_ticket.created, .step.started, .step.paused, .step.resumed, .step.completed, .step.skipped, .step.returned, .moved, .note_added, .cancelled, .completed. data carries the ticket, the step acted on, the current step and who did it; the customer appears only as clientId.
    • PATCH /webhooks/:id changes events, isActive (pause/resume) or filters without changing the URL or the secret.
    • POST /webhooks/:id/test { type } sends one signed sample right away (livemode: false, never retried) and answers { delivered, error }.
    • filters: { jobStationIds } sends job ticket events only for steps at those stations. Without it nothing changes.
    • GET /webhooks returns filters and lastDelivery for each endpoint.
    What to do: Nothing for existing endpoints. An endpoint subscribed to "*" starts receiving job_ticket.* events once the company uses job tickets — ignore types you do not handle.
  19. Incremental product and stock sync

    GET /products takes updatedSince, includeInactive and includeVariants, and GET /inventory takes updatedSince, so a store can sync only what changed since its last run.

    • updatedSince is an ISO 8601 date or date-time; any other value answers 400 INVALID_FIELD.
    • includeVariants adds variants: [{ id, visibleId, sku, name, unitCost, isActive, attributes }] to every product, with unitCost being the price the variant sells at.
    • Every product row carries isActive, so a sync can tell a deactivated product from a deleted one.
  20. Exact SKU lookup, variants included

    GET /products/sku/:sku?exact=true matches only your own SKU — the product's or one of its variants' — ignoring case and surrounding spaces, and returns data: { product, variant }.

    • Without exact=true the lookup works as before, manufacturer SKU included.
  21. Product creation returns visibleId, and names the product that owns a SKU

    POST /products/create returns visibleId alongside productId. When the SKU is already taken, the 400 now carries code PRODUCT_SKU_EXISTS, existingProductVisibleId and existingProductIsActive.

    • The status and the error text are the same as before, so existing error handling keeps working.
    • PUT /products/edit/:id answers the same way when changing to a SKU another product uses.
  22. Payment methods for online stores: Bit, PayPal and digital wallets

    payments[].paymentMethod on receipts, invoice-receipts and credit notes accepts bit, paypal and wallet (Apple Pay / Google Pay).

    • They are printed on the document under their own names and reported to the Tax Authority export like their nearest existing method, never as cash.
    • Installments remain available on creditCard only.
  23. Phone and address on an inline client

    The client object on document creation takes phoneNumber and address { street, city, zip, country }. They are saved when the request creates the client, and the address becomes its primary address.

    • A client matched by identifyClientBy is never changed by what the request sends.
    • An explicit client.addressId still takes precedence over address.
  24. identifyClientBy: "email" matches the exact address

    Matching an inline client by email compares the whole address, ignoring case and surrounding spaces. Dana@Example.com finds dana@example.com, and never a client whose address only contains it.

  25. Find a client by exact email or by phone

    GET /clients takes exactEmail (exact, case-insensitive) and phone (digits only, local or international Israeli form). The existing email filter stays a substring match.

  26. Action roles for store integrations

    New action roles documents.view, clients.view and webhooks.manage, and inventory.view now also opens the stock endpoints, so a store key can run on action roles alone.

    • documents.view: GET /documents/id/:visibleId and GET /documents/by-external-id/:externalId.
    • clients.view: GET /clients, /clients/id/:visibleId, /clients/entity/:entityId and its addresses.
    • webhooks.manage: GET, POST and DELETE /webhooks (and /grow/webhooks) without an owner key.
    • inventory.view: GET /inventory, /inventory/:id and /inventory/product/:productId.
  27. GET /apiKeys/me: check which key you hold

    Returns the calling key (id, name, prefix, base role, action roles), its company (id, name, tax id) and its rate limit. Works for a key with action roles only; a non-key session gets 400 API_KEY_REQUIRED.

  28. Own error code for a key whose creator left the company

    A key created by a user who is no longer an active member of the company still gets a 401, now with error.code API_KEY_OWNER_INACTIVE instead of UNAUTHORIZED.

    What to do: If you show a message on 401, tell the user that a company owner needs to create a new key when the code is API_KEY_OWNER_INACTIVE.
  29. E-commerce guide rewritten

    The e-commerce guide now covers the recommended key, matching customers by exact email, safe retries with externalId and Idempotency-Key, reconciliation by external id, and shipping as a product line.

  30. Scanning can answer 402 when the quota is used up

    GET /purchase/scan/extract-from-file/:fileId answers 402 USAGE_QUOTA_BLOCKED when the month's included scans and all purchased scan packages are used up and the company blocks above its quota.

    • The body is { success: false, error: { code: "USAGE_QUOTA_BLOCKED", message } }, with a Hebrew message for the user. Nothing is scanned and nothing is counted.
    • Block is the default above the quota; a company can switch to pay-per-use instead, and buying a scan package unblocks scanning right away.
    What to do: Treat 402 as "ask the business to buy a scan package or allow charges", not as a transient error — retrying does not help.
  31. Documents report: external income and a purchase scope

    POST /reports/documents takes externalIncomeIds, and scope: "purchase" with vendorPaymentIds for a purchase-documents report.

    • externalIncomeIds adds documents issued on the company's behalf by another system; cancelled ones are marked and left out of the totals.
    • Any of documentIds, externalIncomeIds or vendorPaymentIds satisfies the ids requirement; with none of them and no filters the call still answers 400 DOCUMENT_IDS_REQUIRED.
  32. Debt aging per client, and what is not yet invoiced in the client list

    A client's open invoices can be read by days past due without the reports plan, and the client list shows, for every client, the open orders and delivery notes not yet invoiced.

    • GET /clients/id/:visibleId/aging returns totals per bucket (current, 1–30, 31–60, 61–90, 90+ days past due) and the open invoices behind them.
    • GET /clients returns uninvoiced: { count, amount } on every client, by document status.
  33. Client statement (כרטסת) with a running balance

    Every document issued to a client, oldest first, with its debit or credit and a running balance that ends on the client's balance — and a flag on any financial document whose balance entries do not match it.

    • GET /clients/id/:visibleId/statement returns rows, finalBalance (positive = the client owes you), issues and checksEnabled.
    • GET /clients/entity/:entityId: totalObligation is now the debt plus the open orders and delivery notes by document status, and exceedsCredit follows it.
    • expectedBalance and obligationBreakdown on GET /clients/id/:visibleId are kept but should not be relied on; read open orders and delivery notes from openDocuments.
    What to do: If you computed exposure from expectedBalance, switch to openDocuments (or totalObligation on /clients/entity/:entityId).
  34. Installments set on a document override the business setting

    The number of installments saved on a tax invoice is what its payment link offers, above or below the business-wide setting. A document without one follows the business setting instead of one payment.

    • paymentMaxInstallments on POST /documents/create/{type} and PATCH /documents/:visibleId/payment-installments: 1–12 sets the document's own value; null follows the payment provider setting.
    • GET /documents/share/:visibleId/recipients returns paymentMaxInstallments, so a send dialog can show and change it before sending.
    • The customer still picks on the payment page, from one payment up to the number offered.
    What to do: To keep a document on a single payment, send paymentMaxInstallments: 1 rather than null.
  35. Inventory and journal records in the uniform-structure export

    The BKMV export now writes M100 inventory item records for a company that keeps an inventory ledger, and B100 / B110 journal records under full double-entry bookkeeping.

    • recordCounts on /reports/uniform-data reports M100, B100 and B110 alongside A100, C100, D110 and D120.
  36. VAT rate per line on supplier invoices

    A purchase document line can carry its own VAT rate, for a vendor that bills one item at a different rate from the rest — for example 0% on an exempt item and 18% on everything else.

    • POST /purchase/create/{type} takes vatRate (0–100) on each products line. Omit it or send null to use the document rate.
    • POST /purchase/scan/finalize keeps the vatRate of each line item on the document it creates.
    • With mixed rates, a document discount and rounding are spread across the rates, and the PDF summary shows one VAT row per rate.
    What to do: Nothing. Documents sent without line rates are taxed exactly as before.
  37. Credit notes and partial receipts under each open invoice

    The aging and debtors reports list, for each open sales invoice, the credit notes and partial receipts already offset against it, so the remaining amount can be reconciled line by line.

    • Each item in debts may carry adjustments: documentId, documentVisibleId, documentNumber, documentType, kind ("credit" or "payment"), creationDate and a positive amount.
    • totalAmount minus the adjustments equals remainingAmount. A credit note is counted at its own total.
    • The customer statement PDF shows the same rows under their invoice.
    • The field is additive and omitted when an invoice has none. Vendor mode does not return it.
  38. Card installments: a business cap and a cap per deal

    A business can cap how many installments a card payment may be split into, and each document and payment link can carry its own cap. The payer picks the number on the hosted payment page.

    • POST /documents/create takes paymentMaxInstallments (1–12, or null for one payment) — what the customer may choose when paying the document through its payment link.
    • PATCH /documents/:visibleId/payment-installments changes it after issue. It applies to links already sent.
    • POST /grow/payments/payment-page and PATCH /grow/payments/payment-pages/:id take maxInstallments.
    • The payer is offered the lower of the deal's cap and the business cap. A deal with no cap stays at one payment.
    • POST /grow/payments/charge with a paymentNum above the business cap returns 400 INSTALLMENTS_EXCEED_MAX, with the cap in error.maxInstallments.
    What to do: Nothing changes until the business sets a cap. Once it does, a charge with more installments than allowed is rejected — read error.maxInstallments and retry with that number or fewer.
  39. Changed

    Authentication failures return 401

    A missing, unknown or expired API key is now answered with 401 UNAUTHORIZED and a WWW-Authenticate: Bearer header. 403 is kept for a valid key that lacks permission.

    • 401 UNAUTHORIZED — no Authorization header, an unknown key, or a key whose user no longer has access.
    • 403 — the key is valid but its role, company or module does not allow the request.
    • The error body keeps the usual { success: false, error: { status, code, message } } shape.
    What to do: If your client treats 403 as "the key is bad", handle 401 the same way.
  40. Changed

    Malformed input is rejected with 400

    Requests with a non-numeric id, an invalid date, or document amounts the pricing engine cannot compute now get 400 INVALID_FIELD with a JSON body, instead of a 500.

    • Dates in query parameters are accepted as YYYY-MM-DD or ISO 8601.
    • On document create and preview: tax and line discounts must be zero or greater, percentages at most 100, and currencyCode a valid ISO 4217 code.
    • An unknown route is answered with a JSON 404.
  41. Changed

    Stricter list filters and stable paging

    List endpoints now page in a stable order, validate their filters, and count `limit` in records rather than joined rows.

    • Rows that share a sort value are ordered by id, so walking pages never repeats or skips a record.
    • GET /clients and GET /vendors return `limit` clients per page, each with its contacts.
    • GET /clients?type= with an unknown type returns 400 INVALID_CLIENT_TYPE.
    • GET /documents?clientIds= with a token that is not a positive integer returns 400 INVALID_CLIENT_IDS.
    • GET /inventory now filters by `search` (product name, SKU, manufacturer SKU).
    • An empty page of the change feed returns the cursor you sent, so you can keep polling with it.
  42. Client card: reconciled open-document totals

    GET /clients/id/:visibleId adds openDocuments.other, the part of the balance not tied to an open document, so the obligation totals add up.

    • obligationBreakdown.counts.openOrders and openDeliveries now come from document status.
    • GET /clients/entity/:entityId returns 400 INVALID_FIELD for a non-numeric id.
  43. Changed

    Duplicate expenses are rejected with 409

    POST /expenses/create refuses an expense whose vendor already has an expense or a supplier invoice with the same documentNumber, unless allowDuplicate is true.

    • The number is compared after trimming, against the vendor's expenses and its supplier invoices that are not cancelled.
    • An expense with no documentNumber is never checked.
    • The response is 409 with error.code DUPLICATE_EXPENSE.
    What to do: If you record the same vendor document more than once on purpose — for example one invoice split into two expenses — send allowDuplicate: true. Otherwise treat 409 DUPLICATE_EXPENSE as "already recorded".
  44. Retainers every N months

    Retainers take intervalMonths alongside scheduleDay, so a retainer can run quarterly, yearly or every N months on a fixed day.

    • intervalMonths is 1–120 and only applies with scheduleDay. Omitted or null means every month.
    • Every X weeks is intervalDays = 7·X.
    • GET /retainers and GET /retainers/:id return intervalMonths.
  45. Total stock in the products list

    GET /products returns totalStock for each product: the on-hand quantity summed across all of the company's warehouses.

  46. External income in the documents list

    GET /documents accepts externalIncome=include or externalIncome=only to list invoices that another party issued on the business's behalf. Without the parameter the list is unchanged.

  47. Customer ledger as Excel, and sending it

    The customer ledger can be exported as an Excel sheet and emailed to the customer, alongside the existing PDF.

    • POST /reports/customer-ledger/excel — the same ledger as a spreadsheet.
    • GET /reports/customer-ledger/recipients — who the ledger can be sent to.
    • POST /reports/customer-ledger/send — sends it; a failed recipient does not stop the others.
  48. Credit notes without a linked invoice

    A refund (credit note) no longer has to reference an invoice. When it does, the credit is applied against the linked invoices, capped at what is left on each.

    • Crediting more than an invoice's remaining amount returns REFUND_EXCEEDS_INVOICE.
    • Crediting an invoice-receipt also issues a matching negative receipt.
    • payments on a credit note records money actually returned to the customer.
  49. Document lines: negative amounts rejected

    Document creation rejects lines with a negative quantity (units). Every line needs a description, and rounding follows one documented rule.

    What to do: Send a reduction as a discount (discount / discountType) instead of a negative line.
  50. Clearing retainer fields with null

    PUT /retainers/:id accepts null to clear intervalDays, scheduleDay, endDate and maxRuns. Omitting a field still leaves it unchanged.

    • A retainer must keep at least one schedule; clearing the last one returns 400 RETAINER_SCHEDULE_REQUIRED.
  51. Reference checked against the API

    Every documented endpoint was compared with the server, and the reference now matches what it returns. A test keeps each documented path tied to a real route.

    • Write endpoints return the resource itself, not a { data } wrapper.
    • Endpoints that return a file (PDF, ZIP) are marked as such.
    • Lists that return everything at once are named on the Pagination page.
    What to do: If you built against these pages before this date, compare your response parsing with the current examples.
  52. Rate limit per API key

    Each API key gets 600 requests per minute. Responses carry X-RateLimit-* headers, and a 429 RATE_LIMITED includes Retry-After.

  53. Idempotent document creation

    Send an Idempotency-Key header and an externalId on document creation, so a retry after a timeout returns the original document instead of issuing a second one.

  54. Incremental sync for documents

    GET /documents accepts updatedSince and returns a cursor, so a sync reads only documents that changed, including cancellations and settlements.

  55. Document webhooks

    Subscribe to document events, such as document.created, document.status_changed and document.approval_number.assigned, alongside the payment events. Deliveries are signed and retried.

  56. Execution statuses, internal notes and allocations

    Track a document's operational status separately from payment, keep an internal note on it, and read its allocation history.

    • GET /documents filters by origin and executionStatus.
    • An unknown ?type= now returns 400 INVALID_DOCUMENT_TYPE with the supported types, instead of every document.
    • Lines can be marked nonBillable.
  57. One error shape and one pagination contract

    Errors carry a machine-readable code in { success: false, error: { status, code, message, issues } }, and paginated lists accept limit/offset or page/pageSize, capped at 200.

  58. One-time items on recurring billing

    Add a one-off charge to the next run of a retainer or a standing order without changing its regular amount.

  59. Documents-by-origin report and document design settings

    Break down issued documents by how they were created (API, POS, retainer and more), and set the document design through PUT /settings.

  60. Issuing while the Tax Authority is unavailable

    With allowMissingApprovalNumber: true, a document is issued without an allocation number and marked PENDING, and the number can be completed later.

  61. Charge once and keep the card

    A payment page created with entityId and saveCard: true charges the customer and saves the card to them, so later charges need no new page.

Last updated