geodzk
A link shortener that knows two things about a visit: that it happened, and when.
geodzk turns a long URL into a short one under a personal namespace: https://geodzk.com/l/alice/party. It exists to put a link somewhere a link does not normally go — a wedding invitation, a poster, a plant label, a business card, the back of a photograph.
It knows two things about a visit: that it happened, and when. That restraint is the product's argument rather than a footnote to it, and most of what follows is that argument applied.
Where to go
| Page | What is on it |
|---|---|
| Getting started | Setting up an account, making your first link, and why a code never comes back. |
| What this unlocks | The capabilities this service is actually for, what makes them possible, and where it is worse than the alternatives. |
| The API | Authentication, scopes, every endpoint, every error code, every limit. |
| AI instructions | The one page an agent holding a key should read: what it may call, what it must not promise, and what not to retry. |
| Accounts | Roles versus scopes, API keys, two-factor, backup codes, and why your name is a namespace. |
| Privacy | What a visit records, what that costs, and what is deliberately never collected. |
| Masked links | Two modes, the custom-part cost, what the operator can and cannot do, and the limits of the promise. |
| Collections & print | Publishing a collection, embedding it, and the printed cards, QRs and sheets. |
| Operating | The admin plane, the deployment scope, moderation, and running your own. |
The five ideas
Everything else is these five applied. They are worth reading once, because they explain the decisions that otherwise look arbitrary.
- A URL you handed somebody is a promise. A code that has been printed or turned into a QR outlives the row behind it, so a code is never reused, a published collection URL is never reissued, and a username — which is a namespace — is never handed to a second person. Breaking a link is allowed. Silently re-pointing one at somebody else's content is not.
- The box matters more than the threat model. This runs in a container on a machine whose main job is something else, so "can a stranger make this expensive?" is a security question with the same weight as "can they read someone else's data?" — and the answer is a number.
- A guard that can be checked in two places will disagree in two places. Scope enforcement lives in one function; every query touching account data takes an account id. The guard is part of the thing it guards.
- No dead ends, and no lies. Every failure says what happened, whether retrying will help, and what to do next. Every count agrees with its noun.
- Privacy by absence. There is no email column, so there is no "email me a reset link" — and recovery had to be built for real instead.
For a program
Every page here is also available as text to a key holding docs:read, which is ticked by default when a key is made. If you are an AI agent holding a key, read AI instructions first — it is written for you, and it is one page.
curl -s -H "X-API-Key: $GEODZK_KEY" https://geodzk.com/api/docs
curl -s -H "X-API-Key: $GEODZK_KEY" https://geodzk.com/api/docs/ai
The same page as text, for a program: GET https://geodzk.com/api/docs/index — needs a key holding docs:read.