Most link shorteners begin life as a simple redirect service. A user submits a destination URL, the system creates a short code, and future requests resolve that code back to the original address. At small scale, that model can remain elegantly simple. There is one traffic path, one set of protections, and one broad idea of who the product is for.
That simplicity does not survive contact with a real platform.
As Plung matured, we found ourselves serving three very different kinds of traffic at once. The first was anonymous frontend traffic from people who simply wanted to shorten a link without creating an account. The second was authenticated developer traffic from applications that needed stable identity, higher throughput, and plan-aware limits. The third was safety-sensitive redirect traffic, where every request sat at the intersection of user experience, abuse prevention, and operational risk.
The engineering challenge was not merely to add features to a URL shortener. It was to avoid collapsing all of those concerns into one API surface and one trust model. A platform that treats anonymous browser requests, managed developer integrations, and redirect enforcement as the same kind of traffic eventually becomes difficult to secure, difficult to price, and difficult to operate.
We chose a different path. Instead of stretching one interface to serve every need, we split the system into explicit lanes, each with its own assumptions and controls. That decision now shapes how Plung handles public access, internal frontend requests, authenticated API usage, billing, quotas, and link safety.
This post explains why that separation mattered, what it changed in the architecture, and what we learned about building product boundaries early.
Zero friction is a product decision with architectural consequences
One of the defining product choices in Plung is that the core shortening experience should remain fast and low-friction. If someone wants to shorten a link from the public site, they should not have to pause to create an account, verify an email address, or work through an onboarding flow before the product becomes useful.
The moment we chose a zero-account public flow, we also chose not to rely on account identity as the primary primitive for our entire platform. We could not assume that every request came from a logged-in user. We could not move all access control into a single session model. We could not use the same mechanism to govern a public browser form and a production integration running in a developer's infrastructure.
At the same time, Plung was evolving beyond a purely anonymous utility. We added API keys, plan tiers, usage quotas, billing flows, link expiration controls, password protection, custom aliases, batch shortening, dashboard views, and administrative tooling. Those features are difficult to deliver responsibly if every caller is treated as a generic public client.
This is the tension that shaped the current platform. We wanted to preserve the speed of the public experience without weakening the guarantees needed by a developer platform. Put differently, we wanted the homepage to stay simple without forcing the backend to stay naive.
That meant the architecture had to recognize different trust boundaries, not just different features.
Why one API was no longer enough
Once you accept that not all traffic should be treated the same way, the next question is straightforward: where should the boundaries live?
In Plung, the answer became three distinct lanes:
v1 public developer traffic
v2 authenticated developer traffic
api/frontend/* internal frontend traffic
The public v1 layer continues to serve open access use cases. It is intentionally approachable, which makes it useful for experimentation, low-volume automation, and quick integrations that do not need account-managed credentials.
The authenticated v2 layer exists for a different class of work. Once developers need durable identity, plan-based features, higher limits, usage visibility, and billing-backed entitlements, the system needs to reason about who is calling, what plan they are on, and which capabilities should be available to them. That is not a documentation problem. It is an enforcement problem.
Then there is the official frontend itself. Early on, it is tempting to let the public website call the same public developer endpoints. But the moment your site and your external developer audience share the same interface, you lose an important distinction. You can no longer say, with confidence, "this traffic came from our product" versus "this traffic came from an external caller."
So we separated the frontend into its own internal route family. The frontend controller now exposes dedicated endpoints for actions like shortening and stats retrieval, but those endpoints are protected as frontend-only surfaces rather than documented as public developer APIs. That gives the product team room to optimize the official web experience without accidentally expanding the public platform contract every time the frontend evolves.
The important point here is not that versioning alone solves architecture. It does not. What matters is that each surface now carries a different security model, a different operational intent, and a different relationship to the business.
Public traffic should remain simple. Developer traffic should be identifiable and enforceable. Frontend traffic should be trusted only when it satisfies the constraints we define for the official app.
Trust boundaries have to be enforced at runtime
Once the lanes are separate, the real work begins. A boundary that lives only in documentation is not a boundary. It is a suggestion.
For Plung, that meant turning trust into runtime behavior.
On the authenticated side, v2 requests pass through API key validation and plan-aware enforcement. That allows the platform to distinguish a valid caller from an invalid one, but it also allows us to distinguish between different valid callers. A Free plan key and a Pro plan key are both legitimate, yet they should not receive the same entitlements. The same request shape can be acceptable for one customer and disallowed for another depending on plan, rate, and quota state.
That is where plan enforcement becomes more than a pricing concern. The plan guard in the backend checks monthly API call limits, resource-specific limits such as links and QR codes, static feature flags, and dynamic feature usage drawn from the request body itself. If a request includes a custom alias, password protection, or expiration behavior, the system evaluates that against the caller's plan before any assumption is made that the request should succeed.
Not every capability deserves its own endpoint. Sometimes the cleanest API design is a single endpoint whose behavior varies based on optional fields. But once you do that, the runtime has to understand those fields as policy inputs, not just payload data.
The frontend-only layer uses a different model because it solves a different problem. Instead of API keys, it relies on origin validation, CSRF validation, and, in production, signed request verification. That stack is intentionally different from the developer platform because the official web application is not an external integration.
Just as important, these protections are paired with rate limiting rather than treated as a replacement for it. A well-designed trust boundary assumes that some misuse will still occur. Limits, headers, and consistent enforcement are part of how a system remains predictable under pressure.
One of the broader lessons here is that platforms do not become trustworthy simply by adding authentication. They become trustworthy when every important distinction in the product model is made explicit in runtime control flow. Who is calling, how they are calling, what they are allowed to do, and when they should be stopped all need first-class representation in the system.
Pricing becomes real when it changes system behavior
Many teams think of pricing as a layer above the product: a page, a comparison table, a checkout experience, a billing vendor. That is only half true.
Pricing becomes operationally meaningful when it changes what the backend enforces.
In Plung, the plan model is expressed as concrete runtime limits across four tiers: Free, Hobby, Indie, and Pro. Those tiers do not exist merely to justify a number on a marketing page. They define monthly API call ceilings, monthly link creation limits, QR generation limits, feature access, API key allowances, and per-minute request rates.
That design has two important effects.
First, it gives the product a canonical source of truth. The plan configuration describes the boundaries the rest of the platform should respect. That reduces ambiguity between pricing copy, dashboard behavior, and API enforcement.
Second, it forces billing and quota tracking to participate in the runtime path rather than living as disconnected administrative systems.
Usage tracking is a good example. Fast-moving API traffic needs counters that are cheap to update, so the usage service follows a Redis-first path for monthly metrics. But billing-grade accountability cannot depend on a single volatile store, so those counters also persist through a MongoDB-backed record model. That combination gives us a fast operational path and a durable recovery path. If Redis is unavailable or incomplete, the system can still reason about current usage instead of becoming blind.
The same principle applies to subscription state. Paddle is part of the plan lifecycle. Price identifiers map back to platform tiers, billing periods resolve into subscription state, and plan changes eventually need to reconcile with the permissions the backend enforces. If that loop breaks, the product starts saying one thing while the runtime does another.
This is why mature developer products treat billing as a systems concern. Checkout is the visible part. The harder part is making sure plan state, usage state, and entitlement state all converge on the same answer when a request arrives.
Safety does not end when a link is created
A link platform has another responsibility that sits alongside security and billing: it has to remain trustworthy after links go live.
This is where URL shortening becomes operationally more serious than it looks from the outside. A short link hides the full destination from casual inspection. That makes the product convenient for legitimate use, but it also means the service has to take responsibility for the kinds of destinations it allows and the conditions under which a redirect should be interrupted.
In Plung, safety starts before creation. The platform includes a Safe Browsing service that checks submitted URLs against Google's threat matching API. That gives the creation path a way to reject destinations already associated with malware, social engineering, or other known harmful activity.
But safety cannot rely only on external threat feeds. Some abuse patterns emerge in the alias layer, where malicious intent shows up not in the destination alone but in how the short link tries to present itself. To address that, Plung includes reserved alias protection, malicious pattern matching, and an override system that allows administrators to explicitly allow or block exceptions. That makes alias validation a managed system rather than a static word list.
Redirect behavior also matters. Links may be valid, expired, password protected, or unsafe. Each of those states needs a clear operational outcome. Some requests should redirect immediately. Others should stop at a verification or safety boundary. The goal is not only to block harmful behavior, but to do so transparently enough that the system remains understandable to legitimate users.
Finally, no automated safety system is complete without a human reporting path. Plung exposes abuse reporting with its own throttling and stores those reports for review and action. Good platform safety combines automated checks, administrative control, and a clean path for feedback when reality outruns heuristics.
The broader lesson is that trust for a link platform is not a single feature. It is a chain of decisions that begins when a URL is submitted and continues through alias selection, redirect execution, policy enforcement, and incident handling.
The durable lesson
The most useful lesson we have taken from this work is that mature developer products are defined by boundaries.
Which traffic is public? Which traffic is trusted? Which traffic is paid for? Which traffic should be stopped entirely? If the platform cannot answer those questions precisely, then it will eventually struggle to scale its product model, its security posture, or its business model.
For Plung, becoming a platform did not mean abandoning the simplicity of a URL shortener. It meant protecting that simplicity by refusing to route every use case through the same assumptions. The anonymous public user, the authenticated developer, and the safety-sensitive redirect are all part of the same product, but they are not the same kind of system interaction.
In practice, that has meant treating APIs, quotas, billing, and safety as parts of one architectural story. Not because every user sees those systems directly, but because strong boundaries are what make the visible experience feel reliable.
Utility products often look simple from the outside. The work of making them dependable is deciding, early and clearly, where simplicity ends and system design begins.
Written by
Plung Engineering