Saleline Missing from Lightspeed API Account

NiranlohNiranloh Member Posts: 5

We have a custom application that we use for accounting sales data in an external system. We will query Sales and Salelines from the Lightspeed API account and register them in our system to track changes in quantities via sales and returns. We have experienced a handful of instances in which we have some abnormality with our external system's quantities, and will see that it is related to an API update. When I use Postman to hunt down the offending Sale and associated Saleline, the Saleline returns a 404. This is very strange because it will often skip over the Primary ID of the Saleline and reference the next in the same Sale. For example:

Sale with saleID 1427 has a SaleLine with saleLineID 2114 for an Item (itemID 6758) that was returned. In our application's history we are seeing that there should also be a SaleLine with saleLineID 2113 as a part of the above sale and with a Item (itemID 8560) which was sold. When I review the inventory and sales data in our Lightspeed UI there is no recorded sale of Item(8560) and its inventory is still at the pre-sale value. When I attempt to query SaleLine(2113) I receive the following response:


  "httpCode": "404",

  "httpMessage": "Not Found",

  "message": "Object of type 'SaleLine' not found with primary ID '2113'.",

  "errorClass": "Exception"


I don't understand how a SaleLine, which had implications for our Application, as it could read it shortly after it occurred, could suddenly cease to exist. Is this a UI action or some other strangeness?

This is a real example, so if there are any engineers reviewing this Discussion, I would love for you to delve into our Account (I can give you our account ID separately) and try to help us determine if there is some system issue or a issue on our end not using best practices.


  • gregaricangregarican Member Posts: 702 

    Sounds like your own application's history could possibly be mis-wired somehow. Especially if you aren't seeing it in the inventory logs in the LS Retail web client.

    What I would do is go into the LS Retail web client, ring a dummy sale, watch it port over via the API, and then ring a refund of the dummy sale. Watch that port over via the API. If you look at that test transaction set in near real-time you should be able to determine where the disconnect is. Since I don't think you can actually delete a transaction record in LS Retail. You can archive certain records, but otherwise it seems really odd!

  • maurisourcemaurisource Partner Posts: 35 partner

    Hi Niran,

    can you post the request sent to the API in order to create the SaleLine?

  • gregaricangregarican Member Posts: 702 

    I don't think he's using the API to create any of these records. He's just querying them via the API to push into his accounting system...

  • NiranlohNiranloh Member Posts: 5

    That is correct Gregarican. All sales are created in Lightspeed at the register by a sales associate. It is very odd as it happens incredible infrequently. At this point I think maybe .1% of the time. Which does make it really simple to resolve (if caught), but also really easy to miss.

    As far as I have observed, sales and refunds seem to work perfectly well for our purposes, at least independently. Mostly, I want to make sure that we are using the data properly or accounting for all the various ways that things can occur (It could be an misuse of the API on our end, it could be poor practice on the associate's end, or it could be an actual issue with Lightspeed's service or API).

    I will do some tests with sales and refund combined and see if I can learn more. It is quite strange to me that the SaleLine is just totally gone.

  • gregaricangregarican Member Posts: 702 

    It might have something to do with your query that looks at sale lines. If a sale is voided, for example, then it wouldn't appear in your query if the voided=false parameter is excluding those transactions. Say an operator rings a sale, that sale is ported into accounting via the API, and then the sale is voided after your API query. Figure voids should be infrequent, so perhaps that might explain why you don't see it a lot?

  • NiranlohNiranloh Member Posts: 5
    edited February 2019

    I think you might be on to something Gregarican. I spoke to the associate and I learned that they looked up the price of the item by scanning it onto a new transaction, and then subsequently removed it before later completing the same transaction, which had been left open, with a new line (just happened to be a return). Not exactly a voided issue. . . but it clued me in.

    This is what I believe happened:

    Our application had already registered the existence of the saleline with the item before it was removed and then the sale completed with other salelines.

    If a Sale is not marked as completed, we check for updates on it and its SaleLines. In case anything has changed, like prices, discounts, quantities, etc, the SaleLines will now reflect this. I think the mistake I made was assuming that some record would exist, I did not account for the exception that it might not. We use the query parameter "load_relations" to access the full list of SaleLines, so as reduce the number of API calls. So, when the update attempts to get new data about the SaleLine, there is nothing there, and therefore nothing to update. Due to the aforementioned "load_relations" there isn't even a 404 issue, because are not calling the SaleLineID directly. When the Sale is eventually marked as Complete=True, all formerly registered SaleLines, even the ones that no longer exist, get updated in our system.

    So I think I have found myself caught with my pants down around my premature optimization. . . Not doing all checks on records or entities, making assumptions about record states in an attempt to save time, effort, or bucket space, and probably some other silly things. . . Its basically all my fault *facepalm*. We are fortunate that these events happen rarely, and that the conditions have to be pretty specific for them to happen at all.

    I have two proposed options for resolving this issue. I can 1) have my application do an extra check to see if the associated sale lines still exist before committing the registered values. Or 2) not even register an event unless the sale is completed to begin with. Any thoughts about which of these routes (or another) might be better?

  • gregaricangregarican Member Posts: 702 

    If it were me I'd only write away transactions that are completed. For example, I pull daily sales/refund transactions via the API and port them into a local SQL Server DB.

    So I have query parameters such as archived=false&voided=false&completed=true to only pull those transactions that I am assuming are fully written away in LS Retail. I have a lot of load_relations involved as well, since I want to pull as much linked data as I can, seeing I'm limited in terms of API call limits, record limits per page, etc.

  • NiranlohNiranloh Member Posts: 5

    I was leaning that way too. I think simply adding those query parameters should make it a pretty simple patch.

Sign In or Register to comment.