nano-api / count
One number, and not worth
a table of its own
Increments are a single SQL statement, so two callers at the same instant are never handed the same number. Read it back as JSON, or as an SVG badge that needs no token And because of that same property, it doubles as a sequence allocator.
Free. Signup is one curl and the key comes back in the response. No form, no
card, nobody to ask.
- POST /v1/counters/downloads → 1
- POST /v1/counters/downloads?by=5 → 6
- POST /v1/counters/downloads?by=12 → 18
Read it anywhere. Only your code increments it.
Increment from anywhere
curl -X POST "https://count.nano-api.com/v1/counters/downloads?label=downloads" \
-H "Authorization: Bearer $NANO_API_KEY"
# {"counter":{"value":1,"badge_url":"https://count.nano-api.com/b/pub_…svg", …}} ?by=5 to add more, PUT to set an exact value. The counter is
created on first use.
Reading it back
 ?label= and ?color= override it per request. Or read the raw
number from a browser, since the JSON endpoint is CORS-open:
curl -s https://count.nano-api.com/b/pub_….json
# {"name":"downloads","value":12300} Invoice numbers are the same problem
This is the counter's best use, not a feature bolted onto it. Handing out invoice
numbers means exactly what a counter already guarantees: two callers at the same
instant must never get the same one. The atomic increment is the allocator,
and ?by=100 reserves a block in one round trip rather than a hundred.
One thing has to be forbidden. A tally may be corrected ("the download count is really
12300" is reasonable), but invoice 42 twice is an accounting problem. Create it with
?monotonic=true and the counter keeps everything it already did, minus the
ability to move backwards: a negative step or a lower PUT gets a
409.
# create it once with the guarantee
curl -X POST "https://count.nano-api.com/v1/counters/invoice-2026?monotonic=true" \
-H "Authorization: Bearer $NANO_API_KEY"
# then just allocate. ?by=100 returns 102, so 3..102 are yours
curl -X POST "https://count.nano-api.com/v1/counters/invoice-2026?by=100" \
-H "Authorization: Bearer $NANO_API_KEY"
# and it will not go back
curl -X PUT "https://count.nano-api.com/v1/counters/invoice-2026?value=2" \
-H "Authorization: Bearer $NANO_API_KEY" # 409 The flag is fixed at creation, because a counter that could drop the guarantee would not have one. It promises no allocation is handed out twice, not that the numbers have no gaps: a caller that dies after taking 43 loses 43. Where unbroken numbering is a legal requirement, that has to happen in the same transaction as the invoice, and no counter over HTTP can do that.
Three ways I got this wrong by hand
- 1
Two writers, one lost count
The obvious version reads the number, adds one, writes it back. Two callers who read the same moment write the same value, and an increment vanishes. Here adding and returning is one statement, so there is no gap to lose it in.
- 2
The key ends up committed to git
A badge is an image, and an image URL cannot send a header, so it ends up in a README or a template with the key in it. Each counter gets its own unguessable public id instead: it shows that one number, cannot change it, and says nothing about the rest of your account.
- 3
The number counts caches, not code
Put a CDN in front of a page-hit counter and it either freezes or inflates. Reading never increments here. You increment from your own code, when the thing you actually care about happened.
Using it with the others
Count the rows an export wrote, then ping Pulse when it finishes. One number for the badge, one alert when the job stops.