OptoSoft Developers API – India

Build on the same API that powers OptoSoft optical retail software. The OptoSoft REST API lets your own systems create customers, capture spectacle and contact-lens prescriptions, raise sales orders, generate GST invoices, record receipts and read live dashboard figures — over plain JSON, secured with JWT bearer tokens.

This reference documents 85 endpoints across 8 modules, with request and response fields, worked examples and error handling. It is written and maintained by the OptoSoft team in Ahmedabad, India, and reviewed against the live OpenAPI specification every month.

JWT bearer auth JSON request & response 85 documented endpoints Reviewed monthly

Introduction

The OptoSoft REST API gives your software direct, programmatic access to an optical store’s data — customers and their prescriptions, sales orders, GST invoices, receipts, stock and daily takings. It is the same API used by the OptoSoft web application and the OptoSoft Android POS app, so anything those products can do, your integration can do too.

Typical uses include syncing customers into a CRM or marketing platform, pushing orders in from a website or marketplace, pulling invoice data into an accounting package such as Tally or Zoho Books, feeding a business-intelligence dashboard, or building a custom in-store app on top of your existing OptoSoft data.

API access is issued per company and branch. It is included with an active OptoSoft subscription at no extra licence fee. Contact us to have credentials created, and see pricing for subscription plans.

Postman collection

Every endpoint on this site is packaged as a ready-to-import Postman collection — all 85 requests, grouped into the same 8 modules, with pre-filled example bodies, 218 saved response examples (success and error cases) and a login script that captures your token automatically.

OptoSoft REST API — Postman Collection

Collection format v2.1 · 85 requests · 8 folders · 29 variables · 218 saved responses

Download JSON

Import and run in under a minute

  1. Download the file above, then in Postman choose Import and drop it in.
  2. Open the collection’s Variables tab and set username and password.
  3. Run 01 Authentication & Account → Login. Its test script stores the JWT in {{token}} for you.
  4. Set companyId, branchId and yearId (from Get my profile and List financial years), then send any request.

Collection-level auth is already set to Bearer {{token}}, so every request except login inherits it. Encrypted identifiers have their own enc* variables — paste real values in as you obtain them from earlier responses (see Encrypted identifiers).

Numeric fields use unquoted variables — for example "companyID": {{companyId}}. Postman substitutes the value before sending, so the request that goes out is valid JSON ("companyID": 18). Quoting them would send a string where the API expects an integer. Any JSON warning shown in Postman’s body editor is cosmetic.

Base URL

All endpoints are served over HTTPS from a single host. Every path in this reference is relative to it.

https://api.opto-soft.com

So POST /api/Auth/login means POST https://api.opto-soft.com/api/Auth/login. Plain HTTP is not supported. The machine-readable OpenAPI 3.0 specification is published at /swagger/v1/swagger.json.

Authentication

The API uses JWT bearer tokens. Exchange your OptoSoft username and password for a token once, then send that token on every subsequent call.

1. Request a token

curl -X POST https://api.opto-soft.com/api/Auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "userName": "your-optosoft-username",
    "password": "your-password"
  }'

2. Send it on every request

curl https://api.opto-soft.com/api/Orders/cancellation-reasons \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json"

Every endpoint documented here requires the Authorization header. A missing, malformed or expired token returns 401 Unauthorized. Full details are on the Authentication page.

Company, branch and year context

OptoSoft is multi-tenant and multi-branch, and Indian accounting is organised by financial year. Most search and save requests therefore carry three scoping fields:

FieldMeaning
companyIDYour OptoSoft company (tenant). Fixed for your account.
branchIDThe store or outlet. A multi-store chain has one ID per branch.
yearIDThe financial year the record belongs to. Resolve the current value from GET /api/Common/GetYears.

Note that these are typed inconsistently across the API: some endpoints take them as numbers (int64), others as encrypted strings. Each endpoint’s field table states which form that endpoint expects — follow it exactly.

Encrypted identifiers

Many request and response fields are opaque encrypted identifiers rather than plain numbers. You will see this wherever a schema name is prefixed Encrypted, and wherever an ID field is typed string instead of int64 — for example customerID, salesOrderID and itemTypeID.

The rule for handling them is simple:

  • Never construct one yourself and never assume it is a number in disguise.
  • Read it from a previous response and echo it back verbatim, including case.
  • Do not URL-encode or re-encode it beyond normal query-string escaping.
  • Treat it as opaque and unstable — do not persist it as a long-term primary key or parse meaning out of it.

Some list responses return both forms, such as EncryptedInvoiceListDto which carries an encrypted id alongside a numeric plainId. Where both exist, use the encrypted id for follow-up API calls and keep plainId only for your own reconciliation.

In the wire format they appear as Base64-like strings, for example "CustomerID": "Q2ZQdGhSZVhBaVlXTnpaWFF3TWk0d01B". OptoSoft confirms these are AES-encrypted values.

The AES key and mode are not published, so you cannot generate or decode these yourself. That is by design and it is not a blocker: every encrypted ID you need is handed to you by an earlier response, so the echo-back pattern covers every documented workflow. If you need to map your own internal numeric IDs onto OptoSoft IDs directly — typically for a bulk migration — contact the OptoSoft team for the key-exchange details.

Pagination

The API uses two different paging conventions depending on the module. Check the field table for the endpoint you are calling.

StyleFieldsUsed by
Page number pageNumber, pageSize Orders search, receipts, item search
Row range fromPage, toPage Customers, invoices, doctors, WhatsApp templates

Paged responses also come in two shapes. Almost every paged endpoint returns Items / Total / PageNumber / PageSize:

{
  "Items": [
    { "...": "one object per record" }
  ],
  "Total": 248,
  "PageNumber": 1,
  "PageSize": 25
}

The one exception is POST /api/Invoice/List, which uses TotalRows / Data instead:

{
  "TotalRows": 132,
  "Data": [
    { "...": "one object per record" }
  ]
}

Do not assume one envelope. Key your parser off the endpoint. Each endpoint page below shows its real response, so check there before writing a deserialiser.

Response envelopes

Across the 60 endpoints with a published response there are six distinct top-level shapes. This is the single most common source of integration bugs, so check the endpoint page before you model anything:

ShapeEndpointsWhere
plain object17Single-record reads, e.g. customer detail, login.
bare array16Simple lists, e.g. GetYears, cancellation-reasons.
{ Items, Total, PageNumber, PageSize }8The standard paged envelope.
{ success, message, … }8Save/acknowledge operations. Read success, not just HTTP 200.
{ success, data }6The Invoice helper reads plus the two SaveSale endpoints — the payload sits under data.
bare string4Some 200s (and most errors) return a bare JSON string.
{ TotalRows, Data }1Only POST /api/Invoice/List.

Response conventions

Request and response field naming differ, which catches most integrations out on day one:

ContextCasingExample
Request bodiescamelCasecustomerID, firstName, pageNumber
Read responsesPascalCaseCustomerID, Name, Items
Save/ack responsescamelCasesuccess, message, customerID

Two further quirks worth handling defensively:

  • Some booleans are returned as strings — for example "IsActive": "true" on customer rows, while "IsCurrentYear": false is a real boolean elsewhere.
  • Dates appear both as ISO timestamps ("2024-01-15T09:15:00") and as display strings ("15/01/2024", dd/MM/yyyy) depending on the field.

Sort order is controlled by an orderBy string (a column name, optionally followed by DESC). Omit it to accept the module default.

Errors

Error bodies are not uniform, and they are not RFC 7807 problem details despite the OpenAPI specification declaring a ProblemDetails schema. In practice there are two shapes.

Validation failures (400) return a JSON object:

{
  "success": false,
  "message": "Mobile No is required."
}

Auth and not-found failures (401, 404) return a bare JSON string — not an object:

"No logged in please login to get the access."

"Customer not found."

A strict deserialiser will throw on the string form. Read the error body as raw text first and only then attempt to parse it as an object, or branch on the status code. Do not model every error as { success, message }.

Successful save operations return an acknowledgement carrying the new entity’s encrypted id:

{
  "success": true,
  "message": "Customer saved successfully.",
  "customerID": "Q2ZQdGhSZVhBaVlXTnpaWFF3TWk0d01B"
}
StatusMeaningWhat to do
200SuccessParse the body. Note that a successful call can still return an empty data array.
400Validation failedRead detail. Usually a missing scoping field or a malformed date.
401UnauthenticatedToken missing, malformed or expired. Call /api/Auth/login again and retry once.
404Not foundThe order, receipt or record does not exist in the requested company, branch and year scope.
500Server errorRetry with backoff. If it persists, contact support with the request path and timestamp.

Do not treat HTTP 200 as unconditional success on save operations. Several save endpoints return 200 with a result object describing the outcome. Always inspect the response body before marking a record as synced on your side.

Rate limits and fair use

No hard rate limit is published in the OpenAPI specification. In practice, treat the API as a business system rather than a bulk-export pipe:

  • Keep sustained traffic under roughly 60 requests per minute per branch.
  • Reuse a single bearer token across calls rather than logging in per request.
  • Page through large result sets instead of requesting very large pageSize values.
  • Poll search endpoints on a date range (every few minutes), not in a tight loop.
  • Back off exponentially on 500 responses.

If you need a higher sustained throughput for a migration or a nightly sync, let us know in advance.

API reference by module

85 endpoints are documented across 8 modules. If you are starting from scratch, read Authentication first, then Customers & Prescriptions.

60 of the 85 endpoints now show a real, OptoSoft-supplied response example — look for the Example response — 200 OK block on each endpoint. The remaining 25 (mostly the Quick Sale dropdown and cart helpers) do not yet have a published response shape; their request contracts are accurate, but treat their response fields as unconfirmed until we publish them.

Authentication & Account

Obtain a JWT bearer token with your OptoSoft credentials, then read the signed-in user's profile and daily working context.

3 endpoints →

Customers & Prescriptions

Create and update customers, search the customer register, detect duplicates, and manage spectacle and contact-lens prescriptions (SPH, CYL, AXIS, ADD, PD) plus the referring-doctor master.

13 endpoints →

Sales Orders

Search sales orders with paging, read a single order and its line items, list orders carrying an outstanding balance, change order status and cancel an order with a reason.

10 endpoints →

Invoices

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 →

Payments & Reporting

Read receipts against a customer or sales order, page through the receipt register with filters, and pull aggregated dashboard figures for a branch and financial year.

3 endpoints →

Quick Sale

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 →

Catalog & Master Data

Item types, categories and sub-categories, item search, the country/state/financial-year masters, and server-rendered invoice and receipt PDFs.

15 endpoints →

WhatsApp Messaging

Register a WhatsApp Business Account against a branch and manage the message-template library, including syncing approval status back from Meta.

7 endpoints →

Versioning and change policy

The current specification version is v1. OptoSoft reviews the live OpenAPI specification against this documentation every month and records additions, removals and field changes below.

Treat new fields appearing in a response as non-breaking — parse defensively and ignore properties you do not recognise, so that an additive change never breaks your integration.

DateVersionChange
2026-07-26 v1 Initial publication of the OptoSoft Developers API reference — 85 endpoints across 8 modules.

Frequently asked questions

Does OptoSoft have a REST API?

Yes. OptoSoft exposes a JSON REST API at https://api.opto-soft.com, described by an OpenAPI 3.0 specification. It covers 85 documented endpoints across authentication, customers and prescriptions, sales orders, GST invoices, receipts and reporting, quick sale counter billing, catalog and master data, and WhatsApp messaging configuration.

Is there a Postman collection for the OptoSoft API?

Yes — a ready-to-import Postman collection (format v2.1) is available free. It contains all 85 endpoints grouped into 8 folders, pre-filled example request bodies, 218 saved response examples (success and error cases), 29 pre-declared variables, and a login test script that captures your JWT into the {{token}} variable automatically, so every other request authenticates without further setup.

How do I authenticate with the OptoSoft API?

Post your OptoSoft username and password to /api/Auth/login to receive a JWT. Send that token on every subsequent request in the Authorization header as Bearer {token}. Every endpoint except login requires a valid bearer token.

Is the OptoSoft API free to use?

API access is included with an active OptoSoft subscription, which starts at ₹6,000 per year in India and US$399 per year internationally. There is no separate API licence fee. See OptoSoft pricing, then contact us to have API credentials issued for your company and branch.

Can I use the OptoSoft API outside India?

Yes. The API is available to OptoSoft customers worldwide, including the United States, United Kingdom, Australia, Canada, UAE, Germany, France, Japan and Brazil. Tax fields follow the Indian GST model (CGST, SGST, IGST); customers outside India can set tax rates to zero or use the taxNotApplicable flag on receipts.

What data format does the OptoSoft API use?

All requests and responses use application/json over HTTPS. Request fields are camelCase while read responses are PascalCase — see Response conventions. Error bodies are not uniform: validation failures return an object like { "success": false, "message": "..." }, while 401 and 404 return a bare JSON string, so read the error body as text before parsing it. The PDF endpoints return binary application/pdf rather than JSON.

Does OptoSoft provide webhooks?

OptoSoft operates inbound webhooks for its own WhatsApp Business and voice integrations, but does not currently publish outbound webhooks for partner systems. To detect new orders or receipts, poll the search endpoints such as POST /api/Orders/search using a date range.

Ready to build? Request API access and we will issue credentials for your company and branch, or read more about the optical software features the API exposes.

Chat with us Call us