Why it's safe
Two ledgers, and they must agree .
A voucher is a bearer instrument. Whoever holds it can spend it, so the only question that matters is whether the one in front of you is real and unspent. we answer that by keeping the record in two places that cannot both be edited by the same hands.
bullmark
Holds the voucher itself — who has it, what it is worth, whether it has been used.
Sends the hash never the contents
axowl
Holds the anchor — a fingerprint of that record, and its own clock saying when it arrived.
axowl never sees what a voucher says. It is handed a fingerprint and stores it with a timestamp of its own. That is the whole arrangement, and it is what makes the two sides independent: changing a voucher means changing its fingerprint, and the fingerprint is not ours to change.
What is covered
The fingerprint is taken over these
Not the whole row — a named list, so it is knowable rather than a matter of trust. change any one of them and the fingerprint stops matching.
The product the brand who holds it its redeem code its serial number the consumer price the price it grants when it expires whether it has been used when it was used the holder's email
The last three joined in august 2026 , and they were the important ones. A spent voucher flipped back to unused in the database used to keep its fingerprint and pass every check — the redemption was recorded elsewhere, so the row itself could say it had never been touched. It cannot any more.
Two things are deliberately left out , because putting them in would create false alarms. Reservation is a lock, not a fact about value — a voucher held for thirty seconds at a till is not a changed voucher. expiry is already derivable, since the expiry date is itself sealed; sealing the state as well would mean a voucher verified clean on monday and failed on tuesday with nobody having touched it. A checker that cries wolf is one people learn to click past.
Where each attack dies
Four ways to cheat from the inside, and what stops them
Edit a voucher in the database
Drop the price, push the expiry out, put your own name on it. The fingerprint changes and no longer matches the anchor held at axowl. recomputing our own copy does not help — the copy that decides is not in our database.
Spend the same voucher twice
Redemption is now inside the seal, so setting it back to unused changes the fingerprint. And the redemption is separately recorded as its own sealed entry, chained to the one before it — two records would have to agree on the lie, and one of them is not ours.
Mint one that was never issued
Issuing seals the whole batch as one fact: this many, at this price, until this date. A hundred-and-first voucher contradicts a record already written. And a new anchor carries axowl's clock, not ours — it can be created today, never last year.
Quietly move it to someone else
The holder is inside the seal, so a voucher cannot change hands by editing a field. Handing one over closes the giver's copy and issues the receiver their own, carrying the same serial number, with both halves in the record. There is no version of the story with only one side.
Copied codes
What if someone copies my QR?
A QR is not the voucher. It is a pointer to one numbered row on our side, and the row is the voucher. So a picture of a QR is worth exactly what the row behind it is worth at the moment someone presents it — which is the useful way to think about every case below.
A made-up code
Redeeming looks the code up; it does not read a value off the image. A code that was never issued points at nothing, however convincing the QR around it looks. There is no way to draw a voucher into existence.
A copy of a real one
A copy is the same code, so it is the same voucher — not a second one. The first redemption is sealed into the row; every later attempt, from the copy or the original, is told it has already been used. Ten screenshots are still one voucher.
A screenshot kept before selling it
Handing a voucher over — a gift, a resale — closes the giver's row and issues the receiver a new row with a new code , under the same serial number. The code in the old screenshot now points at a closed row. Selling a voucher and then racing the buyer to spend it does not work.
A code someone else saw first
This one is real, and we would rather say so: a voucher is a bearer instrument, and a brand redeeming by code is not told who is holding the phone. Scanning a QR does not give the code away — a scan shows that the voucher is genuine and unspent, and the code only to its signed-in holder and the issuing brand — but a code you post or read out is a code someone else can use. Treat it like a gift-card number. A brand that wants it closed can ask us which vouchers its signed-in customer actually holds and let them pick from that list, instead of accepting a typed code — then a copied code has nowhere to be entered.
And whichever way it goes, it is on the record. Issue, hand-over, reservation and redemption are each a sealed entry chained to the one before. A brand can pull the full chain for any of its own vouchers — contents included — and re-derive every fingerprint itself, so "who spent this, and when" has an answer that does not depend on our say-so.
Brand credit
Can we quietly print it?
Brand credit is money-shaped: a brand charges it, issues vouchers against it, and cashes out what it earns. So the fair question is not whether an outsider can break in — it is whether we can add a line to our own ledger and hope nobody notices.
The ledger only grows
Entries are appended, never edited or removed. A correction is another entry saying what it corrects, so the mistake and the fix both stay visible. There is no version of the balance with the awkward line taken out.
Every entry is sealed and linked
Each one carries the fingerprint of the one before it. Changing an old entry breaks every entry after it, so the cost of a single quiet edit is rewriting the whole chain — in two places, one of which is not ours.
An insider is not exempt
Database access is not the same as ledger access here. Someone with full rights to our production database can still change a row — they simply cannot make the anchor at axowl agree with it afterwards. That is the whole point of keeping the second copy somewhere our administrators are not administrators.
You can audit it without asking us
A brand can hand its own entry ids to an accountant, who re-derives the fingerprints from the open chain and checks that the sums add up. The check does not route through bullmark, so there is nothing for us to be helpful about.
What we do not claim
We verify an email. That is the line .
We do not check passports, run identity bureaus, or pretend to know who is behind an address. A seal proves a record has not been altered — it does not make an unverified claim true, and a company that blurs those two is selling you a feeling.
So here is the exact promise: this voucher, at this price, was issued to this email address, at this time, and has not been touched since. the email is the one the account authenticated with, never a form field someone typed. Anything past that address is outside what we can prove, and we would rather say so than let you find out later.
Check it yourself
You do not have to take our word for it
Every sealed entry is readable, and the maths that produced it is open. Hand the chain to our javascript sdk — or to anything that can do sha-256 — and re-derive the fingerprints yourself. The check runs entirely on your side; it asks bullmark nothing.
GET /integrity/events/VoucherInstance/{id}
It returns hashes and verdicts, never payloads or redeem codes — so it can stay open without turning into a way to read other people's vouchers.
Start the loop
No cash upfront .
List your startup How it works