Hourmark

How it works

What happens between starting a timer and an invoice marked paid, in plain words. Where it's something you can check yourself, there's a way to try it.

01

Getting the numbers right

Money is the one thing an invoice can't get wrong.

From hours to lines

50 min → 1 h

When you turn tracked time into an invoice, the entries for a client are grouped by what you called them, added up, and rounded up to the next 15 minutes, a common freelancer convention. Each group becomes one line at the client's hourly rate.

Every line remembers whether it's charged per hour or per item, so time reads as “1 h 30 min at ₦45,000/h” on the invoice, and a fixed price as “1 × ₦500,000”. A bare “1.5” doesn't tell your client what was counted.

Once an invoice uses an entry, the entry is marked as billed, so the same hour can't end up on two invoices.

Try itTrack 50 minutes, then make an invoice from it. The line says 1 h, not 50 min: rounded up to the next 15 minutes.

Why totals always match

₦12,150.00 = 1,215,000 kobo

Money is never stored as a decimal. ₦12,150.00 is kept as the whole number 1,215,000 kobo, and every currency gets its own number of decimal places, so the yen gets none. That rules out the classic floating-point drift where 0.1 + 0.2 isn't quite 0.3.

Each line is rounded once, the discount comes off before tax, and tax is rounded once, from a rate stored as a whole number of basis points (7.5% is 750). The phone, the web page and the PDF all use the same small package of shared code for this, so a total in the app matches the page your client sees, to the last kobo.

Invoice numbers that never collide

INV-0007

INV-0007 is claimed inside the database, in the same transaction that saves the invoice, so two phones saving at the same moment can't both get number 7. If saving fails, the number goes back; a deleted draft's number isn't reused.

02

Your client's side

What your client sees, and what you learn from it.

A link that's private without a password

/i/7Qx…f2

Each invoice gets its own link with a long random code in it, about as guessable as a password nobody has. The link isn't listed anywhere and the page tells search engines not to index it.

The page can't read your database directly. It asks one narrow database function for exactly one invoice by its code, and the function only answers for invoices you've sent: drafts never show, and voiding an invoice turns its link off.

Try itVoid a sent invoice, then open its link: it says the invoice can't be found.

How “Viewed” works

viewed

When the page opens in a browser, it tells the database once. The database records the first time, and only if the person opening it isn't you: your own views don't count. Link previews in chat apps don't run the page's script, so pasting the link into WhatsApp doesn't count either. Only the time is kept, not who opened it or from where.

Try itOpen your invoice's link while signed in on the web. It stays Sent. Open it on another phone, and it turns Viewed.

The email, and the PDF

One tap, one email

Emails are sent by the web server, so the key for the email service never lives on your phone. The PDF attached to the email is drawn by the same code as the download on the invoice page, from the same numbers. A double tap sends one email, not two, and the same invoice can't be emailed twice within a minute.

03

Your data

Who can see it, how you get in, and how you leave.

Each account sees only its own

Your rows only

Every table has row-level security: the database itself checks, on every read and write, that the record belongs to whoever is signed in. It doesn't rely on the app remembering to filter. Even a bug in the app couldn't show you someone else's clients.

Signing in without a password

You sign in with a six-digit code sent to your email. There's no password to reuse, forget or leak.

Leaving

Deleted, straight away

Deleting your account, in the app or on the web, removes your business details, logo, clients, time and invoices straight away, in one step. The full list is in the privacy policy.