Case · a Kip-Up product

The receipt leaves the system and the tax office accepts it

In Peru a sale isn't over when the customer pays: it's over when SUNAT, the tax office, accepts the receipt — and each one has three calendar days to get there. Kuantera is the piece that makes that trip: it builds the document, signs it and sends it, and it is written from scratch, with no middleman in between.

What it looks like

Fifteen seconds, from an empty screen to the receipt filed: pick the customer, add a line, and on submit the server signs and sends. The status updates on its own.

A real issue against the tax office's test environment: receipt B001-16 goes out for S/ 36.00, sits «in the queue», and at the end SUNAT answers code 0, accepted. What's stored isn't a «sent» flag: it's the official acknowledgement, the signed XML and the PDF.

How it works inside

A Peruvian electronic receipt is a UBL 2.1 XML with a digital signature inside it, wrapped in a ZIP and handed over by SOAP. There is no library doing that here: it is written in the project, in packages/sunat, because that is exactly where it's decided whether the document is valid or gets rejected over one misplaced figure.

The signature is the part that isn't negotiable. Every receipt is signed with the digital certificate and tax-office credentials of the business issuing it, never mine nor the agency's: before SUNAT, the issuer is them. Using your own credentials to issue on behalf of others would mean registering as an electronic service provider, which is a different business and a different liability.

Sending doesn't block the sale. The API accepts the receipt, numbers it and returns it right away; a separate worker delivers it to SUNAT and retries when the service is down, which happens more often than you'd expect. That's why the panel shows honest states — queued, sent, accepted, observed, rejected — instead of a «done» that means nothing.

Each company sees only its own data, and that holds in the database, not in the code: the tables use row-level security and the role the API connects with cannot bypass it. If a query ever forgets to filter by company, it doesn't return someone else's rows — it returns nothing.

What it is and what it isn't

It's tested against the tax office's test environment: invoices, receipts, credit and debit notes, withholding and service charge. What hasn't happened yet is issuing with a real taxpayer ID in production, and until that day I won't call it finished.

And one thing I learned while preparing this case: when plastic bags are involved, SUNAT rejects the document if the number of bags doesn't match the quantity on the line. I found it by issuing, not by reading the spec, and it's filed as a bug with its XML attached. That's the difference between saying something works and having watched it work.

Do you issue tax receipts and fight your invoicing tool?

Systems that file with the tax office from the inside, without copying data into another screen and without depending on a third party for the part that decides whether the sale exists.

Let's talk →