Sales Orders
A sales order is the central transactional record in OptoSoft: what the customer ordered,
what it costs, when it is due for delivery, how much has been paid, and where it currently
sits in the fulfilment workflow.
In an optical store an order usually cannot be delivered immediately — lenses go to
a lab for surfacing and fitting. The order therefore moves through a status lifecycle and
accrues receipts (advances and final payments) along the way. These endpoints let you
read that state and drive it forward.
Order paths are not consistently typed. Most take an
encrypted string ID, but /api/Orders/{salesOrderId}/items
takes a numeric int64. Others key on the
human-readable salesOrderNo rather than an ID at
all. Each endpoint below states which it expects — check before wiring it up.
Searching orders
POST
/api/Orders/search
Bearer token
The primary order-listing endpoint. Every field is an optional filter, and paging
uses the pageNumber /
pageSize style. This is the endpoint to poll
on a date range if you need to detect new orders.
Request body
| Field | Type | Required | Description |
| pageNumber | int32 | Required | 1-based page index. |
| pageSize | int32 | Required | Rows per page. Keep to 50 or below. |
| yearID | int64 | Optional | Financial year. Strongly recommended — without it you scan every year. |
| customerID | string | Optional | Encrypted customer ID, to list one customer’s orders. |
| salesOrderNo | string | Optional | Order number, exact or partial. |
| customerName | string | Optional | Partial match on customer name. |
| customerMobile | string | Optional | Customer mobile number. |
| branchName | string | Optional | Filter a multi-store chain by branch name. |
| date | string | Optional | Single order date. |
| fromDate | string | Optional | Start of a date range. Use with toDate. |
| toDate | string | Optional | End of a date range. |
| status | string | Optional | Order status filter. |
| acceptedBy | string | Optional | Staff member who took the order. |
| deliveryMode | string | Optional | Collection or delivery mode. |
| deliveryDateTime | string | Optional | Promised delivery date. |
| netAmount | string | Optional | Exact net amount. |
| discount | string | Optional | Discount amount. |
| orderBy | string | Optional | Sort column, optionally with DESC. |
Example request
curl -X POST https://api.opto-soft.com/api/Orders/search \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"pageNumber": 1,
"pageSize": 25,
"yearID": 9,
"fromDate": "2026-07-01",
"toDate": "2026-07-26",
"orderBy": "Date DESC"
}'
Response
A paged envelope: totalRows plus a
data array of order summaries.
| Field | Type | Description |
| id | string | Encrypted sales order ID. Use this on follow-up calls. |
| salesOrderNo | string | Human-readable order number shown to the customer. |
| customerName | string | Customer name. |
| customerMobileNo | string | Customer mobile number. |
| branchName | string | Originating store. |
| date | date-time | Order date. |
| deliveryDateTime | string | Promised delivery date. |
| deliveryModeName | string | Delivery or collection mode. |
| acceptedBy | string | Staff member who took the order. |
| netAmount | double | Order value after discount and tax. |
| totalDiscount | double | Total discount applied. |
| totalReceipt | double | Amount received so far. Balance is netAmount - totalReceipt. |
| itemCount | int32 | Number of line items. |
| statusID | int32 | Numeric status. Pass this to the status-change endpoint. |
| status | string | Display label for the status. |
Example response
{
"totalRows": 248,
"data": [
{
"id": "ENCRYPTED_SALES_ORDER_ID",
"salesOrderNo": "SO/2026/001842",
"customerName": "Anita Shah",
"customerMobileNo": "9876543210",
"branchName": "Satellite",
"date": "2026-07-24T11:20:00",
"deliveryDateTime": "2026-07-29",
"netAmount": 8450.00,
"totalReceipt": 3000.00,
"itemCount": 2,
"statusID": 2,
"status": "In Process"
}
]
}
Reading a single order
GET
/api/Orders/{salesOrderNo}
Bearer token
Fetches a complete order by its human-readable order number —
not by ID. This is what you call when a customer quotes their order number at the
counter or over the phone.
Path parameters
| Name | Type | Required | Description |
| salesOrderNo | string | Required | Order number as printed on the customer’s copy. URL-encode any slashes. |
Example request
curl "https://api.opto-soft.com/api/Orders/SO%2F2026%2F001842" \
-H "Authorization: Bearer YOUR_TOKEN"
Errors
| Status | Cause |
| 404 | No order with that number in the token’s company and branch scope. |
| 500 | Server error. Retry with backoff. |
GET
/api/Orders/{salesOrderNo}/ids
Bearer token
Resolves an order number into the encrypted IDs the rest of the API needs. This is
the bridge between the number a human knows and the identifiers the API expects.
Path parameters
| Name | Type | Required | Description |
| salesOrderNo | string | Required | The order number. |
Response
{
"salesOrderID": "ENCRYPTED_SALES_ORDER_ID",
"customerID": "ENCRYPTED_CUSTOMER_ID"
}
Example request
curl "https://api.opto-soft.com/api/Orders/SO%2F2026%2F001842/ids" \
-H "Authorization: Bearer YOUR_TOKEN"
GET
/api/Orders/{salesOrderId}/items
Bearer token
Returns the line items on an order — frames, lenses, contact lenses and
accessories, with quantity, price, discount and GST breakdown.
Path parameters
| Name | Type | Required | Description |
| salesOrderId | int64 | Required | Numeric sales order ID — not the encrypted string used elsewhere. |
This is the one order endpoint that takes a plain numeric ID. Passing the
encrypted id from
/api/Orders/search here will fail to bind.
Example request
curl https://api.opto-soft.com/api/Orders/104822/items \
-H "Authorization: Bearer YOUR_TOKEN"
GET
/api/Orders/{salesOrderId}/advance-receipt-data
Bearer token
Returns everything needed to take an advance payment against an order: the
customer, the order total, what has already been received and the balance still
outstanding. Call this before recording a receipt.
Path parameters
| Name | Type | Required | Description |
| salesOrderId | string | Required | Encrypted sales order ID. |
Response
| Field | Type | Description |
| salesOrderID | string | Encrypted order ID, echoed back. |
| customerID | string | Encrypted customer ID. |
| customerName | string | Full customer name. |
| customerFirstName | string | Given name, for greetings on the receipt. |
| customerMobileNo | string | Mobile number. |
| custmoerEmail | string | Email address. Note the spelling in the API. |
| soTotalAmount | double | Order total. |
| soTotalDiscountAmount | double | Discount on the order. |
| receiptTotalAmount | double | Total already received. |
| balance | double | Amount still outstanding. |
| statusID | int32 | Current order status. |
| membershipID | string | Encrypted membership ID, if the customer is a member. |
Example request
curl https://api.opto-soft.com/api/Orders/ENCRYPTED_SALES_ORDER_ID/advance-receipt-data \
-H "Authorization: Bearer YOUR_TOKEN"
Errors
| Status | Cause |
| 404 | Order not found in the token’s scope. |
Balances and dropdowns
GET
/api/Orders/with-balance
Bearer token
Lists every order in a financial year that still has money outstanding. This is
the receivables view — useful for a collections report or a payment-reminder
campaign.
Query parameters
| Name | Type | Required | Description |
| yearId | int64 | Required | Financial year to report on. |
Example request
curl "https://api.opto-soft.com/api/Orders/with-balance?yearId=9" \
-H "Authorization: Bearer YOUR_TOKEN"
GET
/api/Orders/dropdown
Bearer token
A lightweight list of one customer’s orders with their balances — designed
to populate a picker when taking a payment, so the cashier can see which order to
apply it to.
Query parameters
| Name | Type | Required | Description |
| customerId | string | Required | Encrypted customer ID. |
| yearId | int64 | Required | Financial year. |
Response
| Field | Type | Description |
| salesOrderID | string | Encrypted order ID. |
| salesOrderNO | string | Order number. |
| soNetAmount | double | Order total. |
| receiptTotal | double | Received so far. |
| balanceAmount | double | Outstanding balance. |
Example request
curl "https://api.opto-soft.com/api/Orders/dropdown?customerId=ENCRYPTED_CUSTOMER_ID&yearId=9" \
-H "Authorization: Bearer YOUR_TOKEN"
Status and cancellation
GET
/api/Orders/cancellation-reasons
Bearer token
Returns the configured cancellation reasons. Fetch this once and cache it to
populate a reason picker.
Response
| Field | Type | Description |
| id | int64 | Reason ID. |
| cancellationReason | string | Display text. |
| isActive | boolean | Only offer active reasons. |
Example request
curl https://api.opto-soft.com/api/Orders/cancellation-reasons \
-H "Authorization: Bearer YOUR_TOKEN"
PUT
/api/Orders/{salesOrderId}/status
Bearer token
Moves an order to a new status — for example from In Process to
Ready for Delivery when the lab returns the job. This is the endpoint a
lab-management or workflow integration drives.
Path parameters
| Name | Type | Required | Description |
| salesOrderId | string | Required | Encrypted sales order ID. |
Request body
| Field | Type | Required | Description |
| statusId | int64 | Required | Target status ID. Read current values from the statusID field on /api/Orders/search results. |
Example request
curl -X PUT https://api.opto-soft.com/api/Orders/ENCRYPTED_SALES_ORDER_ID/status \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "statusId": 3 }'
Errors
| Status | Cause |
| 400 | Invalid status transition, or an unrecognised statusId. |
| 401 | Token missing or expired. |
| 500 | Server error. |
POST
/api/Orders/{salesOrderId}/cancel
Bearer token
Cancels an order and simultaneously settles the treatment of any receipts already
taken against it. Because it touches money, it takes both an order status and a
receipt status.
Path parameters
| Name | Type | Required | Description |
| salesOrderId | string | Required | Encrypted sales order ID. |
Request body
| Field | Type | Required | Description |
| statusId | int32 | Required | Cancellation status to apply to the order. |
| receiptStatusId | int32 | Required | How to treat existing receipts (for example refunded or retained as credit). |
| date | date-time | Required | Cancellation date. |
| transactionDate | date-time | Required | Accounting date the cancellation posts against. |
Example request
curl -X POST https://api.opto-soft.com/api/Orders/ENCRYPTED_SALES_ORDER_ID/cancel \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"statusId": 5,
"receiptStatusId": 2,
"date": "2026-07-26T00:00:00",
"transactionDate": "2026-07-26T00:00:00"
}'
Cancellation is not reversible through the API. There is no
un-cancel endpoint. Confirm the reason and the receipt treatment with the
operator before calling this.
Errors
| Status | Cause |
| 400 | Order already cancelled or invoiced, or an invalid status combination. |
| 401 | Token missing or expired. |
| 500 | Server error. |