List GST invoices with paging and filters, pull the invoice-ready data for a sales order, and post a complete invoice back to OptoSoft.
6 endpoints in this module. Every request needs a JWT bearer token — see Authentication.
An invoice is the GST tax document raised against a sales order. These six endpoints let you list invoices, discover which orders are still awaiting invoicing, pull the invoice-ready data for an order, and post a completed invoice back to OptoSoft.
In an optical store the order and the invoice are usually separated in time: the order is
taken (often with an advance), the lenses are fitted, and the invoice is raised on
delivery. That is why get-invoice-data-by-salesorder
exists — it hands you a pre-filled invoice built from the order, which you complete
and post back.
Indian GST split. Whether tax lands as CGST + SGST (intra-state) or
IGST (inter-state) is decided by the customer’s stateID
against the branch state. Set the customer’s state correctly on
customer upsert
and OptoSoft computes the split for you.
Returns a paged, filtered list of invoices. This is the endpoint an accounting
integration polls to pull sales into Tally, Zoho Books or a GST return workflow.
Paging uses the fromPage /
toPage row-range style.
| Field | Type | Required | Description |
|---|---|---|---|
| companyID | int64 | Required | Company (tenant). |
| branchID | int64 | Required | Store. |
| yearID | int64 | Required | Financial year — the GST return period you are reconciling. |
| invoiceNumber | string | Optional | Invoice number, exact or partial. |
| salesOrderNo | string | Optional | Find the invoice raised against a given order. |
| customerID | string | Optional | Encrypted customer ID. |
| customerName | string | Optional | Partial match on customer name. |
| customerMobile | string | Optional | Customer mobile number. |
| fromDate | string | Optional | Start of the invoice-date range. |
| toDate | string | Optional | End of the invoice-date range. |
| amount | string | Optional | Gross amount filter. |
| netAmount | string | Optional | Net amount filter. |
| totalRows | string | Optional | Echo field used by the OptoSoft grid. Leave unset. |
| orderBy | string | Optional | Sort column, optionally with DESC. |
| fromPage | int32 | Optional | First row of the range. |
| toPage | int32 | Optional | Last row of the range. |
curl -X POST https://api.opto-soft.com/api/Invoice/List \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"companyID": 18,
"branchID": 24,
"yearID": 9,
"fromDate": "2026-07-01",
"toDate": "2026-07-31",
"fromPage": 1,
"toPage": 50,
"orderBy": "Date DESC"
}'
| Field | Type | Description |
|---|---|---|
| totalRows | int32 | Total matching invoices, before paging. |
| data[].id | string | Encrypted invoice ID. Use this on follow-up calls. |
| data[].plainId | int64 | Numeric invoice ID, for your own reconciliation only. |
| data[].invoiceNo | string | Invoice number as printed. |
| data[].salesOrderNo | string | Originating order number. |
| data[].customerName | string | Customer name. |
| data[].customerMobileNo | string | Customer mobile number. |
| data[].date | date-time | Invoice date. |
| data[].netAmount | double | Invoice value including GST. |
{
"totalRows": 132,
"data": [
{
"id": "ENCRYPTED_INVOICE_ID",
"plainId": 55219,
"invoiceNo": "INV/2026/000913",
"salesOrderNo": "SO/2026/001842",
"customerName": "Anita Shah",
"customerMobileNo": "9876543210",
"date": "2026-07-24T16:05:00",
"netAmount": 8450.00
}
]
}
| Status | Cause |
|---|---|
| 400 | Missing scoping field, or an unparseable date. |
| 401 | Token missing or expired. |
Lists customers who currently have at least one order awaiting invoicing. Step one of the "raise an invoice" workflow — it narrows a large customer register down to just those with pending work.
None. Scope comes from the bearer token.
curl https://api.opto-soft.com/api/Invoice/get-customers-for-invoice \
-H "Authorization: Bearer YOUR_TOKEN"
For a chosen customer, lists their orders that are ready to be invoiced. Step two of the workflow.
| Name | Type | Required | Description |
|---|---|---|---|
| customerId | string | Required | Encrypted customer ID from the previous call. |
curl "https://api.opto-soft.com/api/Invoice/get-sales-orders-for-invoice?customerId=ENCRYPTED_CUSTOMER_ID" \
-H "Authorization: Bearer YOUR_TOKEN"
Returns every order in the given company, branch and year that is still awaiting an invoice — the branch-wide view, rather than the per-customer view above. Use it to build a "pending invoicing" worklist.
| Field | Type | Required | Description |
|---|---|---|---|
| companyID | int64 | Required | Company (tenant). |
| branchID | int64 | Required | Store. |
| yearID | int64 | Required | Financial year. |
curl -X POST https://api.opto-soft.com/api/Invoice/GetOrdersForNewInvoice \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "companyID": 18, "branchID": 24, "yearID": 9 }'
The key endpoint of this module. Given a sales order, it returns a fully populated
invoice draft — customer, line items, GST breakdown and totals — ready to
be reviewed and posted back via
save-invoice-data.
| Name | Type | Required | Description |
|---|---|---|---|
| salesOrderId | string | Required | Encrypted sales order ID. |
curl "https://api.opto-soft.com/api/Invoice/get-invoice-data-by-salesorder?salesOrderId=ENCRYPTED_SALES_ORDER_ID" \
-H "Authorization: Bearer YOUR_TOKEN"
The response is an OMFastWizardModel —
the same composite object used by
Quick Sale.
Round-trip it: take the returned object, adjust only what you need, and post it
to save-invoice-data. Do not attempt to
build one from scratch.
Commits an invoice. The request body is the full composite
OMFastWizardModel (94 top-level properties,
most of them nested objects and UI display flags).
| Field | Type | Description |
|---|---|---|
| customerModel | object | The customer the invoice is raised against. |
| salesorderModel | object | The order being invoiced, with its line items. |
| receiptModel | object | Payment taken at the time of invoicing, if any. |
| eyeInfoModel | object | The prescription dispensed against this invoice. |
| eyecheckupRecallModel | object | Next eye-test recall to schedule for the customer. |
| purchaseOrderModel | object | Linked lab or supplier purchase order. |
| autoItemTypeSectionList | array | Item-type sections shown in the OptoSoft wizard. |
| sessionID | string | Cart session ID, when the invoice is built from a Quick Sale session. |
| orderDate | date-time | Order date. |
| expectedDate | date-time | Expected delivery date. |
| supplierID | string | Encrypted supplier ID for lab work. |
| fitterID | string | Encrypted fitter ID. |
| priorityID | string | Encrypted job-priority ID. |
| isLensAdded | boolean | Whether a lens line is present. |
| isSpectacleLensInOrder | boolean | Whether a spectacle lens is on the order. |
| isExternal | boolean | Marks an externally originated transaction. |
| userId | int64 | Operator recording the invoice. |
| branchCity | string | Branch city, printed on the invoice. |
| visitorIP | string | Client IP recorded for audit. |
| showQuickSaleAdd…Section | boolean | Roughly 60 display flags controlling OptoSoft wizard sections (frames, sunglasses, lenses, contact lenses, accessories and so on). Preserve whatever the GET returned; they do not affect the saved invoice. |
Always round-trip this model. Call
get-invoice-data-by-salesorder first, modify
only the fields you need to change, and post the whole object back. Constructing
an OMFastWizardModel by hand is not
supported and will produce incorrect tax totals.
# 1. Pull the pre-filled invoice draft for the order
curl "https://api.opto-soft.com/api/Invoice/get-invoice-data-by-salesorder?salesOrderId=ENCRYPTED_SALES_ORDER_ID" \
-H "Authorization: Bearer YOUR_TOKEN" -o draft.json
# 2. Adjust draft.json as needed (dates, payment, remarks)
# 3. Post it back to commit the invoice
curl -X POST https://api.opto-soft.com/api/Invoice/save-invoice-data \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
--data-binary @draft.json
Inspect the response body before treating the invoice as saved. A
200 here confirms the request was accepted,
not necessarily that a document number was allocated.
Rendered invoice PDFs and print-ready HTML come from the catalog module — see
Catalog & Master Data
for /api/Common/invoice/pdf and
/api/Common/invoice/pdf/html.