The counter-billing workflow: build a cart in a temporary session, look up items by barcode or autocomplete, check live stock, then commit the sale, invoice and receipt in a single call.
28 endpoints in this module. Every request needs a JWT bearer token — see Authentication.
Quick Sale is OptoSoft’s counter-billing workflow — the fastest path from a customer walking in to a printed invoice and receipt. It is the largest module in the API at 28 endpoints, and it powers both the OptoSoft web POS and the free Android mobile POS app.
The model is a server-side cart. You open a session, add line items to a temporary order one at a time, adjust quantities and discounts, then commit the whole thing in a single call that creates the sales order, the invoice and the receipt together.
sessionID on your side (a GUID is fine).getItemDetailFromCode, or by autocomplete.saveSalesOrderTemp.GetSalesOrderTemp to get live totals and tax.SaveSale.
The session ID is yours to manage. OptoSoft keys the temporary cart on
whatever string you supply. Use a fresh unique value per transaction, and always call
deleteSalesOrderTempBySession if the customer walks
away, or abandoned carts will accumulate.
Adds one line item to the temporary cart. Call it once per product. For a spectacle lens, the optical powers travel on the line itself — that is how a single order can carry different powers for each pair.
| Field | Type | Required | Description |
|---|---|---|---|
| sessionID | string | Required | Your cart session key. |
| itemID | string | Required | Encrypted item ID from a lookup call. |
| inventoryID | string | Optional | Specific stock unit, when tracking serialised inventory. |
| qty | double | Required | Quantity. |
| mrp | double | Optional | Printed MRP. |
| price | double | Required | Selling price per unit before discount. |
| discountRate | double | Optional | Percentage discount. |
| discountAmount | double | Optional | Flat discount. Use one or the other, not both. |
| sgstRate | double | Optional | SGST percentage for intra-state sales. |
| cgstRate | double | Optional | CGST percentage for intra-state sales. |
| igstRate | double | Optional | IGST percentage for inter-state sales. |
| jobCharges | double | Optional | Lens fitting or lab charges on this line. |
| pairNo | string | Optional | Groups lines into pairs, so one order can hold two complete spectacles. |
| spectacleLensType | int32 | Optional | Lens type for a spectacle-lens line. |
| spherical | string | Optional | SPH power for this lens. |
| cylinder | string | Optional | CYL power. |
| axis | string | Optional | Axis in degrees. |
| addition | string | Optional | ADD power for bifocal or progressive. |
| pd | string | Optional | Pupillary distance. |
| lensFittingHeight | double | Optional | Fitting height for progressive lenses. |
| lensTotalHeight | double | Optional | Total lens height. |
| Group | Fields |
|---|---|
| Computed totals | totalMRP, totalPrice, taxableAmount, sgstAmount, cgstAmount, igstAmount, totalAmount |
| Service tax | serviceTaxId, serviceTaxRate, serviceTaxAmount |
| Optical detail | near, vision, vn |
| Audit | createdBy, createdDate, createdIP |
| Linkage | id, salesOrderID, isOrdered |
Leave the computed total and tax-amount fields unset. OptoSoft calculates them
from qty,
price, the discount and the GST rates.
curl -X POST https://api.opto-soft.com/api/quickSale/saveSalesOrderTemp \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionID": "3f9c1a52-7b40-4e6d-9a11-0d2c8e5b7f31",
"itemID": "ENCRYPTED_ITEM_ID",
"qty": 1,
"mrp": 4500,
"price": 4500,
"discountRate": 10,
"sgstRate": 6,
"cgstRate": 6,
"pairNo": "1"
}'
Reads the current cart back with live totals. Extra charges are supplied here rather than stored on the cart, so the same session can be re-totalled under different charge assumptions.
| Field | Type | Required | Description |
|---|---|---|---|
| sessionId | string | Required | Your cart session key. Note the lower-case d here, unlike sessionID elsewhere. |
| jobCharges | double | Optional | Order-level fitting or lab charges. |
| shippingCharges | double | Optional | Delivery charges. |
| otherCharges | double | Optional | Any other charge line. |
| serviceTax | double | Optional | Service tax rate on charges. |
| isCompositionScheme | boolean | Optional | Set true if the store is registered under the GST composition scheme (no tax shown on the bill). |
| isCustomerStateNotSameAsCompanyState | boolean | Optional | Drives IGST instead of CGST + SGST. |
curl -X POST https://api.opto-soft.com/api/quickSale/GetSalesOrderTemp \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "3f9c1a52-7b40-4e6d-9a11-0d2c8e5b7f31",
"jobCharges": 150,
"isCompositionScheme": false,
"isCustomerStateNotSameAsCompanyState": false
}'
Edits one cart line in place — the quantity, price or discount stepper on a POS screen. Tax and totals are recalculated for you.
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Required | Encrypted temporary-line ID from GetSalesOrderTemp. |
| qty | double | Required | New quantity. |
| price | double | Required | New unit price. |
| discountRate | double | Optional | New percentage discount. |
| discountAmount | double | Optional | New flat discount. |
curl -X POST https://api.opto-soft.com/api/quickSale/update-sales-order-temp-values \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "ENCRYPTED_TEMP_LINE_ID",
"qty": 2,
"price": 4500,
"discountRate": 15
}'
Removes a single line, or a whole pair, from the cart.
| Field | Type | Required | Description |
|---|---|---|---|
| sessionID | string | Required | Cart session key. |
| salesOrderTempId | string | Optional | Encrypted line ID to remove. |
| pairNo | string | Optional | Remove every line in this pair instead of a single line. |
curl -X POST https://api.opto-soft.com/api/quickSale/delete-salesorder-temp \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"sessionID": "3f9c1a52-7b40-4e6d-9a11-0d2c8e5b7f31",
"salesOrderTempId": "ENCRYPTED_TEMP_LINE_ID"
}'
Abandons the whole cart. Call this whenever a transaction is cancelled, and on start-up for any session your client did not finish.
| Field | Type | Required | Description |
|---|---|---|---|
| sessionID | string | Required | Cart session key to clear. |
curl -X POST https://api.opto-soft.com/api/quickSale/deleteSalesOrderTempBySession \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "sessionID": "3f9c1a52-7b40-4e6d-9a11-0d2c8e5b7f31" }'
Resolves a barcode or item code into a full item record with price and tax rates. This is the barcode-scanner endpoint — the fastest way to add a frame or accessory to the cart.
| Name | Type | Required | Description |
|---|---|---|---|
| code | string | Required | Barcode or item code, exactly as scanned. |
curl "https://api.opto-soft.com/api/quickSale/getItemDetailFromCode?code=8901234567890" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the live on-hand quantity for one item. Call it before committing a sale to avoid overselling a frame that is down to its last piece.
| Name | Type | Required | Description |
|---|---|---|---|
| itemId | int64 | Required | Numeric item ID, not the encrypted string. |
curl "https://api.opto-soft.com/api/quickSale/getExactItemStock?itemId=88214" \
-H "Authorization: Bearer YOUR_TOKEN"
Type-ahead search across frames and sunglasses. Use it when the barcode is unreadable or the customer is browsing by brand or model.
| Name | Type | Required | Description |
|---|---|---|---|
| term | string | Required | Partial brand, model or code. Send at least 2 characters. |
| yearId | int64 | Required | Financial year to search stock within. |
curl "https://api.opto-soft.com/api/quickSale/GetFrameSunGlassForAutoComplete?term=rayban&yearId=9" \
-H "Authorization: Bearer YOUR_TOKEN"
Type-ahead search across spectacle lenses. Unlike the frame search, this takes no year parameter.
| Name | Type | Required | Description |
|---|---|---|---|
| term | string | Required | Partial lens name, coating or index. |
curl "https://api.opto-soft.com/api/quickSale/GetSpectacleLensForAutoComplete?term=progressive" \
-H "Authorization: Bearer YOUR_TOKEN"
Searches contact lenses. This one is a POST
with a JSON body rather than a query string, unlike the two autocomplete endpoints
above.
| Field | Type | Required | Description |
|---|---|---|---|
| term | string | Required | Partial brand, power or modality. |
curl -X POST https://api.opto-soft.com/api/quickSale/search-contact-lens \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "term": "acuvue" }'
Resolves an item type by its numeric ID — used to decide which cart section (frame, lens, contact lens, accessory) a scanned item belongs in.
| Name | Type | Required | Description |
|---|---|---|---|
| id | int32 | Required | Numeric item-type ID. |
curl "https://api.opto-soft.com/api/quickSale/get-item-type-id?id=3" \
-H "Authorization: Bearer YOUR_TOKEN"
The commit call. Converts the temporary cart into a real transaction — sales order, invoice, receipt, stock movement and any lab purchase order — in one atomic operation.
The body is the composite OMFastWizardModel,
the same object used by
/api/Invoice/save-invoice-data.
Its top-level structure is documented on the Invoices page.
| Field | Type | Description |
|---|---|---|
| sessionID | string | The cart session to convert. This is what links the call to the lines you added. |
| customerModel | object | The customer. Can create a new one inline during the sale. |
| salesorderModel | object | Order-level values: dates, delivery mode, charges, remarks. |
| receiptModel | object | Payment taken at the counter. Omit to leave the order fully unpaid. |
| eyeInfoModel | object | The prescription being dispensed. |
| eyecheckupRecallModel | object | Schedules the next eye-test recall for WhatsApp or SMS follow-up. |
| purchaseOrderModel | object | Lab order raised for lens surfacing and fitting. |
| orderDate | date-time | Transaction date. |
| expectedDate | date-time | Promised delivery date. |
| supplierID | string | Encrypted supplier ID for the lab job. |
| fitterID | string | Encrypted fitter ID. |
| priorityID | string | Encrypted job-priority ID. |
| userId | int64 | Operator recording the sale. |
Do not retry blindly on a timeout. This call creates financial
documents. If it times out, query
POST /api/Orders/search for the session’s
customer and date range to check whether the order was in fact created before
re-sending.
curl -X POST https://api.opto-soft.com/api/quickSale/SaveSale \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @sale.json
Raises an invoice against an order that already exists, without recreating the order. This is the delivery-day call: the customer collects their spectacles and the tax invoice is generated.
| Field | Type | Required | Description |
|---|---|---|---|
| salesOrderID | string | Required | Encrypted sales order ID to invoice. |
| customerID | string | Required | Encrypted customer ID. |
| sessionID | string | Optional | Cart session, if the invoice was assembled through one. |
| invoiceDate | date-time | Required | Invoice date. Determines the GST return period. |
| isCompositionScheme | boolean | Optional | Set true for composition-scheme stores. |
curl -X POST https://api.opto-soft.com/api/quickSale/SaveInvoiceOnly \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"salesOrderID": "ENCRYPTED_SALES_ORDER_ID",
"customerID": "ENCRYPTED_CUSTOMER_ID",
"invoiceDate": "2026-07-29T00:00:00",
"isCompositionScheme": false
}'
Records a payment. Use it for an advance at order time, for the balance on delivery, or for a standalone payment not tied to an invoice.
The model is large (164 fields) because it doubles as the print payload — it carries branch letterhead, terms and totals for the printed receipt as well as the payment itself. In practice you set a small subset.
| Field | Type | Required | Description |
|---|---|---|---|
| salesOrderID | string | Required | Encrypted order the payment applies to. |
| receiptAmount | double | Required | Amount being taken now. |
| receiptTypeId | int64 | Required | Payment method. Values from GET /api/quickSale/Fetch-Receipt-Type. |
| yearId | string | Required | Encrypted financial-year ID. |
| branchId | int64 | Required | Numeric branch ID. |
| receiptId | string | Optional | Encrypted receipt ID. Omit to create a new receipt. |
| referenceNo | string | Optional | Cheque number, UPI reference or card transaction ID. |
| salesOrderNo | string | Optional | Order number, printed on the receipt. |
| netAmount | double | Optional | Order net amount, for the printed summary. |
| statusId | int32 | Optional | Receipt status, for example cleared or pending. |
| taxNotApplicable | boolean | Optional | Set true for non-GST transactions, including most sales outside India. |
| isForeigner | boolean | Optional | Marks an overseas customer. |
| receiptPrintFormat | int32 | Optional | Which receipt template to render. |
| Group | Purpose |
|---|---|
| Branch letterhead | branchName, branchAddress, branchCity, branchEmail, branchMobile and similar — printed header. Populate from get-branch-details. |
| Tax totals | totalTaxableAmount, totalSGST, totalCGST, totalIGST, rounding, totalDiscount — computed by OptoSoft. |
| Print layout | receiptName, intrenalReceiptName, isExternalReceiptFormat, signature, termsAndConditions. |
| Repair jobs | repairingID, repairingNO — only for repair receipts. |
| Line detail | Item-level arrays mirroring the order, used to render the receipt body. |
curl -X POST https://api.opto-soft.com/api/quickSale/SaveReceipt \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"salesOrderID": "ENCRYPTED_SALES_ORDER_ID",
"yearId": "ENCRYPTED_YEAR_ID",
"branchId": 24,
"receiptTypeId": 2,
"receiptAmount": 3000,
"referenceNo": "UPI-402291837",
"salesOrderNo": "SO/2026/001842"
}'
Lists the configured payment methods — cash, card, UPI, cheque, credit note and
so on. Fetch once at start-up and cache; the IDs feed
receiptTypeId on SaveReceipt.
curl https://api.opto-soft.com/api/quickSale/Fetch-Receipt-Type \
-H "Authorization: Bearer YOUR_TOKEN"
Returns the full detail of one receipt, in the shape needed to reprint it.
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | int64 | Required | Numeric customer ID. |
| receiptId | int64 | Required | Numeric receipt ID. |
| salesOrderId | int64 | Required | Numeric sales order ID. |
curl "https://api.opto-soft.com/api/quickSale/GetReceiptDetails?customerId=30188&receiptId=77120&salesOrderId=104822" \
-H "Authorization: Bearer YOUR_TOKEN"
Lists unredeemed credit notes held by a customer — from returns, cancellations or goodwill adjustments — so they can be applied against a new sale.
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | int64 | Required | Numeric customer ID. |
curl "https://api.opto-soft.com/api/quickSale/get-credit-notes?customerId=30188" \
-H "Authorization: Bearer YOUR_TOKEN"
Eight small lookup endpoints populate the pickers on a POS screen. All are cheap, all are cacheable, and none change during a trading day — fetch them once at start-up.
Referring doctors, in picker form. The fuller doctor master with addresses lives in Customers & Prescriptions.
None.
Staff who fit lenses into frames. Feeds fitterID
on SaveSale.
None.
Labs and suppliers used for lens surfacing. Feeds
supplierID on the purchase order raised with a
sale.
None.
Job priorities — normal, urgent, same-day. Feeds
priorityID and drives the promised delivery
date.
None.
Gender options with their encrypted IDs, for
genderID on customer upsert.
None.
Customer acquisition sources — walk-in, referral, online, campaign. Paged, unusually for a lookup.
| Name | Type | Required | Description |
|---|---|---|---|
| page | int32 | Optional | 1-based page index. |
| pageSize | int32 | Optional | Rows per page. |
curl "https://api.opto-soft.com/api/quickSale/getSources?page=1&pageSize=100" \
-H "Authorization: Bearer YOUR_TOKEN"
Loyalty and membership schemes, with their encrypted IDs. Paged like
getSources.
| Name | Type | Required | Description |
|---|---|---|---|
| page | int32 | Optional | 1-based page index. |
| pageSize | int32 | Optional | Rows per page. |
curl "https://api.opto-soft.com/api/quickSale/getMemberships?page=1&pageSize=50" \
-H "Authorization: Bearer YOUR_TOKEN"
Lists the card types configured for card payments, for the picker shown when
receiptTypeId is a card method.
None.
Returns the branch profile for the token’s scope — name, address, GSTIN,
phone and email. Use it to populate the letterhead fields on
SaveReceipt and on printed documents.
None. Scope comes from the bearer token.
curl https://api.opto-soft.com/api/quickSale/get-branch-details \
-H "Authorization: Bearer YOUR_TOKEN"
Streams the branch logo image for printed receipts and invoices. Returns image bytes, not JSON.
| Name | Type | Required | Description |
|---|---|---|---|
| branchId | int64 | Required | Numeric branch ID. |
| fileName | string | Required | Logo file name, as returned by get-branch-details. |
curl https://api.opto-soft.com/api/quickSale/get-branch-logo/24/logo.png \
-H "Authorization: Bearer YOUR_TOKEN" \
-o logo.png
Returns the minimum supported client version. The OptoSoft Android POS app calls this on launch to decide whether to prompt for an update. Worth calling from your own client too, as a forward-compatibility signal.
None.
curl https://api.opto-soft.com/api/quickSale/app-version \
-H "Authorization: Bearer YOUR_TOKEN"