Back to Blog
Technology6 min read

How Client Portal Links Expire

IN
Invoice Generator TeamAuthor
September 26, 2026Published
Also available in:NederlandsDeutsch

A client portal link is a standing URL a specific client can use, without logging in, to browse every invoice and estimate you've sent them. Unlike a one-off share link tied to a single document, a portal link stays useful indefinitely until it expires or you revoke it — which makes its expiry mechanics worth understanding precisely, since it's the thing standing between a client's continued access and a link you meant to be temporary.

What Actually Gets Created

Generating a portal link creates a row that pairs a client record with a randomly generated token — 24 bytes from a cryptographically secure random source, hex-encoded into a 48-character string — and an expiry timestamp calculated from a number of days you choose at creation time. That token is the entire URL; there's no additional login step layered on top of it. Anyone holding the URL can open it, which is why the token's unguessability, not a password, is what protects the link.

The Default Is 30 Days, but the Range Is 1 to 365

When you create a portal link without specifying a lifetime, it defaults to 30 days. You can shorten that down to a single day for a link you intend to be used once and discarded, or extend it out to a full year for a client relationship where you don't want to keep regenerating links. There's no "never expires" option — every portal link has an expiry timestamp calculated at creation time, even a far-future one, which means a link generated with the maximum 365-day window will still eventually stop working unless you generate a new one before it does.

How Expiry Is Actually Checked

Expiry isn't enforced by a background job that deactivates links once their time is up — the link's row stays exactly as it was created. Instead, every single request that touches the portal — loading the document list, opening an individual invoice — independently compares the stored expiry timestamp against the current time before doing anything else. If the comparison shows the link has expired, the request is rejected immediately with a distinct "link has expired" response, before any client or document data is looked up. That means an expired link doesn't quietly stop working the next time a maintenance job happens to run; it stops working at the exact moment the clock passes the expiry timestamp, on the very next request.

Revocation Works the Same Way, on Purpose

You can also revoke a portal link manually at any time, which stamps a revoked_at timestamp on the row rather than deleting it. Every request that validates a portal token checks for a null revoked_at as part of the same lookup that checks the token exists at all — so a revoked link fails the same way, and at the same point, as one that simply doesn't exist. From the client's perspective there's no difference between "this link was never valid" and "this link used to be valid and got revoked"; both return a not-found response rather than leaking the fact that a link once worked.

Every Successful Request Updates last_used_at

Each time a portal link is used successfully — meaning it passed both the existence and expiry checks — its last_used_at timestamp is updated before the request continues. This happens on every request, not just the first one, so last_used_at always reflects the most recent time the link was actually exercised rather than when it was created. It's a useful signal if you're trying to decide whether a client relationship is still using a portal link you set up months ago, or whether it's safe to revoke.

Why Document Matching Is an Exact Comparison, Not a Foreign Key

A portal link is tied to a specific saved client record, but the invoices that link shows aren't looked up through a foreign key — invoices don't reference client records at all. Instead, the system normalizes both the invoice's billed-to text and the client's stored billing details — lowercasing, collapsing whitespace, trimming — and requires them to match exactly. That's a deliberate tightening: an earlier version of this logic used a looser, substring-based comparison, which had a real failure mode where one client's name being a substring of another client's full billing address could let a portal link surface — or worse, in a differently-scoped check, potentially return — another client's invoice. Requiring an exact match after normalization closes that off, at the cost of a portal link occasionally showing fewer documents than expected if an invoice's billed-to text was typed slightly differently from the saved client record it should correspond to.

What This Means Day to Day

In practice, this design means a portal link is safe to treat as long-lived within its chosen window — it won't silently degrade or leak access to the wrong client's documents — but it isn't something you can hand out once and forget entirely. If you want a client to have permanent-feeling access, the practical move is generating a link with the maximum 365-day expiry and making a habit of refreshing it annually, rather than assuming any option exists to make it permanent outright.

Related Articles

Technology6 min read

How Invoice View Tracking Actually Works

Two separate mechanisms record when a client opens your invoice — a running counter and a detailed event log — and a password-protected share link doesn't count as viewed until the password is entered.

IN
Invoice Generator TeamSeptember 24, 2026
Technology8 min read

How the Comment Notification Digest Batches Client Activity Into One Email

Why a burst of client comments produces exactly one email, not five — and how the rolling delay resets on every new comment.

IN
Invoice Generator TeamSeptember 11, 2026
Technology8 min read

How In-App Notifications Fan Out to Your Team

Why every workspace member gets their own independent notification row, and why you don't get notified about your own actions.

IN
Invoice Generator TeamSeptember 8, 2026
Technology9 min read

The Invoice Audit Trail: Every Event Logged Behind the Scenes

What actually gets recorded when an invoice is viewed, commented on, or changes status — and why the logging never blocks the action itself.

IN
Invoice Generator TeamSeptember 4, 2026
Technology6 min read

How Two-Factor Authentication Protects Your Account

2FA generates a six-digit code that changes every 30 seconds using the TOTP standard — no live connection between your phone and the server is ever required.

IN
Invoice Generator TeamAugust 27, 2026
Technology6 min read

How API Keys Are Stored (And What to Do If You Lose One)

The raw value of your API key is never stored anywhere after the moment you create it — only a one-way hash is kept, which is why a lost key can't be recovered.

IN
Invoice Generator TeamAugust 26, 2026

Mastered Invoicing?

Put your knowledge into practice and create your first professional invoice today.

Create Your Invoice Now