Build on TRIMS with three endpoints and a bearer token.
The complete guide to branded short links, dynamic QR codes, realtime analytics, conversion attribution, and the developer API. Whether you're shortening your first link or wiring TRIMS into your data stack, start here.
Introduction
TRIMS shortens links on your own domain and keeps the analytics behind them: per-click geography and device data, funnels and cohorts, conversion attribution back to the link that earned a sale, dynamic QR codes, and white-label workspaces for clients.
This documentation covers both the product (using the dashboard) and the platform (the REST API, webhooks, and integrations). Every concept links to a hands-on example.
What you can do with TRIMS
- Create branded short links on your own custom domains with memorable aliases.
- Track every click in realtime — geography, device, browser, referrer, and UTM parameters.
- Attribute leads and revenue back to the exact link and fire server-side ad pixels.
- Run A/B tests, geo & device routing, and round-robin rotation on any link.
- Generate styled, dynamic QR codes whose destination you can change any time.
- Invite your team, organize work into workspaces, and ship white-label client dashboards.
- Automate everything through a documented REST API, webhooks, and native integrations.
Quickstart
Get from zero to a tracked short link in four steps.
1. Create your account
Sign up with email or Google. Every new account starts on the generous — unlimited links, unlimited tracked clicks, and 30 days of analytics history. No credit card required.
2. Shorten your first link
From the dashboard, click New link, paste a destination URL, and (optionally) set a custom alias. Hit create — your link is live instantly on the global edge.
curl -X POST https://api.trims.app/api/links \
-H "Authorization: Bearer $TRIMS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://northlight.co/products/launch-2026",
"customCode": "q4-launch",
"workspaceId": "'$TRIMS_WORKSPACE'"
}'3. Share it & watch clicks arrive
Every visit is captured within milliseconds and streamed to your dashboard. Open the link's analytics to see geography, devices, and referrers update live.
4. Add your domain (optional)
Bring your own domain (e.g. go.northlight.co) so links are fully branded. See for the DNS setup.
https://api.trims.app/api. Responses are JSON. Authenticate with a bearer token — see .Core concepts
A handful of objects power everything in TRIMS. Understanding how they relate makes the rest of the docs intuitive.
| Field | Type | Description |
|---|---|---|
| Workspace | object | The top-level container for a brand or client. Holds its own links, domains, members, and billing. You can belong to many. |
| Link | object | A short link: a short code on a domain that redirects to a destination URL, plus its rules (targeting, expiry, password) and analytics. |
| Domain | object | A custom domain (e.g. go.northlight.co) verified for a workspace. Links are minted on the workspace's domains. |
| Tag / Folder | object | Organizational labels and containers used to group and filter links. |
| Customer | object | A tracked visitor tied to conversion events (leads and sales) for revenue attribution. |
| API token | object | A scoped credential used to authenticate REST API requests on behalf of a workspace. |
Custom domains
To brand links on your own domain, add it in Settings → Domains, then create a CNAME record pointing to our edge. SSL is provisioned automatically.
Type Name Value
CNAME go.northlight.co edge.trims.app.The dashboard
The dashboard is your command center. The left sidebar switches between areas; the workspace switcher at the top lets you jump between brands and clients.
- Links — create, search, filter, and bulk-manage every short link.
- Analytics — realtime stream, breakdowns, funnels, cohorts, and ML insights.
- QR codes — design and export styled dynamic QR codes.
- Conversions — customers, leads, sales, and attributed revenue.
- Team — invite members, assign roles, and review the activity log.
- Settings — domains, API tokens, webhooks, billing, and security.
⌘K (or Ctrl+K) anywhere in the app to jump to any link, page, or action instantly.Creating links
A link needs only a destination URL — everything else is optional. Create one from the dashboard's New link sheet or via the API.
/links| Field | Type | Description |
|---|---|---|
| url* | string | The destination the short link redirects to. Must be a valid, absolute http(s) URL. |
| workspaceId | string | Workspace to create the link in. Inferred from the API key if omitted. |
| customCode | string | Custom alias (the part after the domain). If omitted, a random code is generated. |
| domainId | string | Id of the custom domain to mint the link on. Defaults to the platform domain. |
| title | string | A human-readable title shown in the dashboard and social previews. |
| tags | string[] | Tag names to attach. Unknown tags are created automatically. |
| folderId | string | The folder to place the link in. |
| expiresInDays | integer | Auto-disable the link after N days. Pair with expiredUrl for a fallback. |
| password | string | Require a password before the destination is revealed. |
| utmSource…utmContent | string | UTM parameters appended to the destination and stored for reporting. |
const res = await fetch("https://api.trims.app/api/links", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRIMS_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://northlight.co/pricing",
customCode: "pricing",
workspaceId: process.env.TRIMS_WORKSPACE,
tags: ["campaign", "q4"],
title: "Q4 Pricing Page",
}),
});
const link = await res.json();
console.log(link.shortUrl); // → https://go.northlight.co/pricingid, shortCode, shortUrl, and the full set of rules and counters.Aliases, UTMs & metadata
Custom aliases
Aliases make links memorable and on-brand (go.northlight.co/webinar instead of a random code). Aliases are unique per domain. Custom aliases are included on every plan, including Free.
UTM builder
Attach UTM parameters so downstream analytics tools (GA4, your CDP) attribute traffic correctly. TRIMS appends them to the destination and also stores them as structured fields for its own reporting.
{
"url": "https://northlight.co/blog/state-of-links",
"customCode": "newsletter",
"utmSource": "newsletter",
"utmMedium": "email",
"utmCampaign": "march-2026"
}Social previews (OG metadata)
Override the title, description, and image that appear when a link is shared on social platforms. Great for making every shared link look intentional.
Expiration & password
- Set
expiresAtto automatically disable a link at a chosen time, with an optional fallback URL. - Set a
passwordto gate the destination behind a prompt — ideal for private or paid content. - Enable link cloaking to keep your branded URL visible in the address bar after redirect.
Geo & device targeting
Route the same short link to different destinations based on where and how a visitor opens it. (Pro plan and above.)
Geo targeting
Send visitors from specific countries to localized pages. Anyone not matched falls through to the default URL.
{
"url": "https://northlight.co/us",
"geoRules": [
{ "countryCode": "GB", "destinationUrl": "https://northlight.co/uk" },
{ "countryCode": "DE", "destinationUrl": "https://northlight.co/de" }
]
}Device & OS targeting
Point mobile users to an app store and desktop users to the web app, or split by OS (iOS, Android, Windows, macOS, Linux). Perfect for deep links.
| Field | Type | Description |
|---|---|---|
| androidRedirect | string | Destination for Android devices (e.g. Play Store or deep link). |
| iosRedirect | string | Destination for iOS devices (e.g. App Store or universal link). |
| macosRedirect | string | Destination for macOS visitors. |
| windowsRedirect | string | Destination for Windows visitors. |
A/B testing & rotation
Split traffic across multiple destinations to test which converts best, or distribute load evenly. (Pro plan and above.)
A/B testing
Assign weights (that sum to 100) across variants. TRIMS deterministically bucket-assigns visitors and reports conversion by variant.
curl -X POST https://api.trims.app/api/v1/links/{id}/ab-variants \
-H "Authorization: Bearer $TRIMS_TOKEN" \
-d '{
"enabled": true,
"variants": [
{ "destination_url": "https://northlight.co/a", "weight": 50 },
{ "destination_url": "https://northlight.co/b", "weight": 50 }
]
}'Round-robin rotation
Rotation cycles visitors evenly across a list of URLs — useful for affiliate pools or load spreading.
Bulk creation & CSV import
Create many links at once — via the API array endpoint or by uploading a CSV (both Pro and above).
/v1/links/bulk[
{ "url": "https://northlight.co/a", "key": "promo-a" },
{ "url": "https://northlight.co/b", "key": "promo-b" },
{ "url": "https://northlight.co/c", "key": "promo-c" }
]CSV import accepts a url column plus optional title, key, and tags columns. Shared options (folder, tags, UTMs) can be applied to the whole batch.
url,title,key
https://northlight.co/1,Landing One,promo-1
https://northlight.co/2,Landing Two,promo-2QR codes
Every link can generate a dynamic QR code. Because the code encodes the short link (not the destination), you can change where it points after it's printed.
- Style the code with brand colors, rounded modules, and a center logo.
- Track scans as clicks — QR scans flow into the same analytics as web clicks.
- Export as PNG, SVG, or PDF, or bulk-export a whole campaign as a ZIP.
curl https://api.trims.app/api/v1/links/{id}/qr?format=png \
-H "Authorization: Bearer $TRIMS_TOKEN" --output qr.pngAnalytics basics
Every click is captured, enriched, and stored. Open any link to see its analytics, or view the workspace-wide dashboard for the full picture. Basic analytics are available on all plans; deeper reports require Pro.
What we capture per click
| Field | Type | Description |
|---|---|---|
| timestamp | datetime | When the click occurred, to the millisecond. |
| country / city | string | Geo-located from IP via a maintained MaxMind database. |
| device / os / browser | string | Parsed from the user agent and client hints. |
| referrer | string | Where the click came from (domain and full referrer). |
| utm_* | string | UTM parameters carried on the link. |
| bot / vpn | boolean | Whether the click was flagged as automated or VPN traffic. |
Reading a link's summary
/v1/analytics/summary?alias={code}&period=30d{
"total_clicks": 12483,
"unique_visitors": 8121,
"top_country": "US",
"top_referrer": "linkedin.com",
"period": "30d"
}Supported period values include 24h, 7d, 30d, 90d, and all. Analytics history retention depends on your plan (up to unlimited on Premium).
Realtime stream
The realtime feed shows clicks the instant they happen — city, link, and device — streamed over a live connection. It's the same pipeline that powers spike alerts.
- Live click ticker with geography and referrer.
- Active-visitor count updated every few seconds.
- Automatic spike detection with optional notifications.
Funnels, cohorts & retention
Advanced analytics turn raw clicks into decisions. (Pro plan and above.)
Funnels
Define an ordered sequence of steps (e.g. click → lead → sale) and see conversion and drop-off at each stage.
Cohorts & retention
Group visitors by the week they first clicked and watch how many return over time — the classic retention curve, applied to link engagement.
Breakdowns
Slice any metric by country, device, browser, referrer, or UTM. Compare campaigns side by side.
/v1/analytics/funnels?workspace={id}&period=30dML insights
TRIMS runs machine-learning models over your click data to surface what a human analyst would — automatically. (Pro plan and above.)
| Field | Type | Description |
|---|---|---|
| Trend | regression | Linear-regression trend over the period with a p-value so you know if it's statistically significant. |
| Forecast | projection | N-period-ahead click forecast with a confidence band. |
| Anomalies | EWMA z-score | Spike/dip detection that flags unusual traffic the moment it happens. |
| Segments | k-means | Clusters visitors into power / casual / bot-risk groups from behavioral signals. |
| Peak windows | pattern | The days and hours your audience is most active. |
| Dark social | classifier | Estimates the share of 'direct' traffic that's really shared privately. |
curl "https://api.trims.app/api/v1/analytics/ml/{code}?workspace={id}" \
-H "Authorization: Bearer $TRIMS_TOKEN"Conversion tracking
Close the loop between a click and a dollar. Send TRIMS a lead or sale event and it's attributed to the link (and customer) that drove it.
/v1/track/lead/v1/track/salecurl -X POST https://api.trims.app/api/v1/track/sale \
-H "Authorization: Bearer $TRIMS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "cus_8f2a",
"amount": 4900,
"currency": "usd",
"event_name": "Pro subscription"
}'| Field | Type | Description |
|---|---|---|
| customer_id* | string | The customer this event belongs to (see Customers). |
| amount | integer | Sale value in the smallest currency unit (e.g. cents). |
| currency | string | ISO 4217 currency code. Defaults to usd. |
| event_name | string | A label for the conversion, shown in reports. |
Ad pixels
Register the pixels you run on your own site so TRIMS can report what it observes for each one — events, unique actors and revenue, grouped by the event name the pixel tracks. (Pro plan and above.)
Add a pixel under Pixels with its platform, ID and the event name it tracks. TRIMS then matches your recorded leads and sales against that event name and reports them per pixel.
What this does not do yet: TRIMS does not send these events to Meta, Google, TikTok or LinkedIn. Those platforms are told about a conversion by the pixel or Conversions API integration on your own site, not by TRIMS. Server-side forwarding is on the roadmap; until it ships, the numbers here describe what TRIMS observed, not what any platform received.
Customers & attribution
A customer is a tracked identity that ties multiple events together. When you identify a visitor (by email or your own ID) TRIMS stitches their clicks and conversions into a single profile with lifetime value.
/v1/customers{
"id": "cus_8f2a",
"email": "nadia@company.com",
"first_link": "q4-launch",
"leads": 3,
"sales": 2,
"revenue": 124000,
"created_at": "2026-02-14T09:31:00Z"
}Workspaces
Workspaces isolate everything — links, domains, analytics, members, and billing — for a brand or client. Agencies typically run one workspace per client; product teams run one per brand.
- Switch instantly with the workspace switcher (top-left).
- Each workspace has its own custom domains and API tokens.
- Plan limits (domains, members) apply per workspace.
Roles & permissions
Invite teammates and assign a role. Role-based access control is available on Pro and above.
| Field | Type | Description |
|---|---|---|
| Owner | role | Full control including billing and workspace deletion. Exactly one per workspace. |
| Admin | role | Manage members, domains, tokens, and all links. Cannot delete the workspace. |
| Editor | role | Create and manage links, QR codes, and view analytics. |
| Viewer | role | Read-only access to links, dashboards, and reports. |
White-label
On Premium, make TRIMS disappear behind your brand. White-label workspaces get a custom dashboard domain, your logo and colors, and branded PDF/CSV reports your clients can read as a first-class asset.
- Custom dashboard domain (e.g.
analytics.northlight.co). - Logo, accent color, and favicon replacement.
- Branded, shareable public dashboards and exports.
Authentication
The TRIMS REST API uses bearer API keys. Create one in Settings → API (API access requires the Pro plan), choose the scopes it should carry, and copy the key — it starts with trims_ and is shown only once. Send it in the Authorization header on every request.
curl https://api.trims.app/api/links?workspace=$TRIMS_WORKSPACE \
-H "Authorization: Bearer $TRIMS_API_KEY"| Field | Type | Description |
|---|---|---|
| Authorization* | header | Bearer trims_<key>. The key is bound to one workspace and carries a set of permission scopes. |
| Content-Type | header | application/json for requests with a JSON body. |
| workspace | query | The workspace id. Required on most read endpoints (e.g. GET /links?workspace=...). |
Scopes & permissions
Every key carries one or more scopes. Scopes are enforced on each request: a key that lacks the required scope gets a 403 insufficient_scope, even if the key is otherwise valid. Grant a key the least privilege it needs.
| Field | Type | Description |
|---|---|---|
| links.read | scope | Read links and their metadata (GET on /links). |
| links.write | scope | Create, update, and delete links (POST/PATCH/DELETE on /links). Implies links.read. |
| analytics.read | scope | Read analytics for links and workspaces (GET on /analytics/*). |
| read:team | scope | View workspace members and invitations. |
| write:team | scope | Invite, update, and remove members. Implies read:team. |
| admin | scope | Full access — every resource and action, including domains, billing, and key management. Use sparingly. |
write:* scope; a read (GET) is satisfied by that resource's read:* or write:*. An admin key passes everything. Writes to resources without a dedicated scope (domains, billing, keys) require an admin key.{
"code": 403,
"error": "insufficient_scope",
"message": "this API key does not have permission for this operation"
}Links API
Full CRUD over links. Every endpoint is scoped to the key's workspace. Reads need links.read; writes need links.write.
/links?workspace={id}/links/links/{id}/links/{id}List with filters
Filtering, sorting, and pagination are applied server-side across the whole workspace (not just the current page).
curl "https://api.trims.app/api/links?workspace=$TRIMS_WORKSPACE&tags=campaign&search=q4&status=active&sort=clicks&order=desc&limit=50&offset=0" \
-H "Authorization: Bearer $TRIMS_API_KEY"| Field | Type | Description |
|---|---|---|
| workspace* | string | Workspace id to list links from. |
| search | string | Full-text match on short code, title, or destination URL. |
| tags | string | Comma-separated tag names to filter by (OR). |
| domain | string | Filter to a custom domain host (e.g. go.northlight.co) or its id. |
| folder | string | Filter to a folder id. |
| status | string | active · archived · expired. |
| sort / order | string | sort: created_at · click_count · updated_at · title. order: asc · desc. |
| limit / offset | integer | Pagination. limit max 500. The response includes the true filtered total. |
Update a link
import requests
requests.patch(
"https://api.trims.app/api/links/{id}",
headers={"Authorization": f"Bearer {api_key}"},
json={"title": "Updated title", "tags": ["q4", "paid"]},
)Analytics API
Pull the same data that powers the dashboard. Requires analytics.read. Advanced breakdowns (funnels, cohorts, ML) require the Pro plan.
/analytics/{shortCode}?period=30d/analytics/{shortCode}/timeseries?period=30d/analytics/{shortCode}/recent-clickscurl "https://api.trims.app/api/analytics/q4-launch?period=30d" \
-H "Authorization: Bearer $TRIMS_API_KEY"| Field | Type | Description |
|---|---|---|
| period | string | 24h · 7d · 30d · 90d · 12mo · all. Defaults to 30d. |
| countries / devices / browsers | string | Comma-separated filters to narrow the result set. |
| from / to | ISO 8601 | Explicit date range (overrides period). |
Webhooks
Subscribe to events and TRIMS will POST a signed JSON payload to your endpoint whenever they occur. Manage webhooks in Settings → Webhooks or via the API. Webhooks require API access (Pro).
/webhooks| Field | Type | Description |
|---|---|---|
| url* | string | Your HTTPS endpoint that receives event payloads. |
| events* | string[] | Events to subscribe to (see list below). |
| secret | string | Used to sign payloads; verify the signature to confirm authenticity. |
Available events
link.created,link.updated,link.deletedlink.clicked— fired on every redirect (high volume).lead.created,sale.created— conversion events.spike.detected— anomalous traffic alert.
{
"event": "sale.created",
"created_at": "2026-03-02T12:04:11Z",
"data": {
"customer_id": "cus_8f2a",
"link": "q4-launch",
"amount": 4900,
"currency": "usd"
}
}Verifying signatures
Each delivery includes an X-Trims-Signature header — an HMAC-SHA256 of the raw body using your webhook secret. Recompute and compare to reject spoofed requests.
import crypto from "node:crypto";
function verify(rawBody, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}OAuth & scopes
Building an app that acts on behalf of other TRIMS users? Use the OAuth 2.0 authorization-code flow instead of static tokens.
/oauth/authorize/oauth/token- 1Redirect the user to /oauth/authorize with your client_id, redirect_uri, and requested scopes.
- 2The user approves; TRIMS redirects back with a short-lived authorization code.
- 3Exchange the code at /oauth/token for an access token (and refresh token).
- 4Call the API with the access token; refresh it when it expires.
Rate limits & errors
Rate limits
Two limits apply together, and both are counted per workspace across all of its tokens: a per-minute rate that bounds bursts, and a monthly request quota that is the actual ceiling for the billing period. Minting extra tokens does not raise either one.
| Field | Type | Description |
|---|---|---|
| Free | — | API access is not included. A workspace that downgrades keeps a reduced allowance so existing integrations degrade rather than break. |
| Pro | 600 / min · 100,000 / month | Per workspace, across all tokens. |
| Business | 1,500 / min · 500,000 / month | Per workspace, across all tokens. |
| Premium | 3,000 / min · 2,000,000 / month | Per workspace. Higher ceilings and dedicated capacity are negotiated. |
Every response carries your current position, so you never have to guess:X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset describe the per-minute window, and X-RateLimit-Quota-Limit, X-RateLimit-Quota-Remaining and X-RateLimit-Quota-Reset describe the month. Once you pass 80% of the monthly quota, X-RateLimit-Quota-Warning appears — watch for it and slow down rather than waiting to be cut off.
Exceeding either limit returns 429, but they are not the same condition and should not be handled the same way. A burst rejection carries code: "rate_limit_exceeded" and a small Retry-After, so backing off works. An exhausted monthly quota carries code: "quota_exceeded" and a resetsAt timestamp that may be days away — retrying will not help, and the plan needs raising. Requests refused by either limit do not consume monthly quota.
Link-creation ceilings
Separately from the API limits above, link creation is capped per hour and per day. These are anti-abuse ceilings, not quotas on how many links you may own: the total number of links stays unlimited on every plan, and redirects are never metered, throttled, or stopped — a link that exists always resolves.
| Field | Type | Description |
|---|---|---|
| Anonymous (no account) | 10 / day per browser | The public shortener on the homepage. The counter is shown live as you use it. Signing up removes it. |
| Free | 100 / hour · 500 / day | Far above any manual workflow; sized to stop scripted bulk creation. |
| Pro | 1,000 / hour · 10,000 / day | Comfortably above a large CSV import or bulk run. |
| Business | 2,500 / hour · 25,000 / day | Per account. |
| Premium | 5,000 / hour · 50,000 / day | Per account. Raise on request. |
Exceeding one returns 429 with code: "link_quota_exceeded", the window that tripped (window: "hour" or "day"), limit, used, remaining, a resetAt timestamp and a Retry-After header — so a client can say exactly when creation resumes instead of guessing. Read the current position at any time from GET /api/shorten/quota.
Error format
Errors return the appropriate HTTP status and a JSON body. Plan-gated features return 403 with a machine-readable code.
{
"error": "Advanced analytics require the Pro plan.",
"code": "upgrade_required",
"feature": "advanced_analytics",
"requiredPlan": "pro"
}| Field | Type | Description |
|---|---|---|
| 400 | Bad Request | Malformed input or validation failure. |
| 401 | Unauthorized | Missing or invalid token. |
| 403 | Forbidden | Valid key but insufficient scope (insufficient_scope) or plan (upgrade_required). |
| 404 | Not Found | Resource doesn't exist or isn't in your workspace. |
| 409 | Conflict | Duplicate alias or domain. |
| 429 | Too Many Requests | Rate limit exceeded; retry after the given delay. |
Using the API from your stack
fetch and curl, and the full spec is served at /api/v1/openapi.json if you would rather generate a client.Creating a link with nothing but fetch:
const res = await fetch("https://api.trims.app/api/v1/links", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRIMS_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ url: "https://northlight.co/launch", key: "launch" }),
});
const link = await res.json();
console.log(link.shortUrl);npx openapi-typescript https://api.trims.app/api/v1/openapi.json -o trims.d.tsIntegrations
REST API or outbound webhooks — both are live.These are the integrations we plan to ship:
- Slack — get spike alerts and daily digests; shorten links with a slash command.
- Zapier / Make — trigger workflows on any TRIMS event, no code required.
- Shopify / Stripe — pipe orders in as sale conversions for true revenue attribution.
- Bitly import — migrate your existing links and history in one click.
Security
Security is built in, not bolted on.
- 2FA (TOTP) — protect accounts with authenticator-app two-factor and recovery codes.
- Encryption — TLS 1.3 in transit, AES-256 at rest for sensitive fields.
- Automatic SSL — every custom domain gets a managed certificate.
- Bot & VPN detection — filter automated traffic so your metrics stay honest.
- Malware scanning — destinations are checked so your brand never fronts a bad link.
- Audit logs — every workspace records who changed what, and when.
info@trims.app. Please do not open a public issue for undisclosed vulnerabilities.Billing & plans
Four tiers. Free includes unlimited links and unlimited tracked clicks with 30 days of history; paid plans add depth, longer retention, more domains and team features. Prices below are per month, billed annually.
| Plan | Price | Highlights |
|---|---|---|
| Free | $0/mo | Unlimited links & clicks · 1 domain · aliases & QR · 30-day history |
| Pro | $15/mo | Every feature unlocked (early access) · fair limits · 2-year history |
| Business | Upcoming | Higher limits for teams & agencies · 25 domains · 20 members |
| Premium | Upcoming | Unlimited scale · white-label · audit logs · retention controls |
See the full comparison on the pricing page. Upgrade or downgrade at any time. Your links keep redirecting on every plan, including after a downgrade.
403 with code: upgrade_required and the app opens the plan picker automatically.Frequently asked questions
Is there really no click limit on the free plan?
Correct — Free includes unlimited short links and unlimited tracked clicks, with 30 days of analytics history. Redirects are never metered or throttled, on any plan. Paid plans add deeper reporting, longer history, more domains, and team features.
Can I use my own domain?
Yes. Every plan includes at least one custom domain (Free: 1, Pro: 5, Business: 25, Premium: unlimited). Add a CNAME and SSL is provisioned automatically.
What happens to my links if I downgrade?
Your links keep redirecting. Features above your new plan become read-only, and you'll be prompted to upgrade if you try to use them again.
Do you offer an API on every plan?
The REST API and webhooks are available on Pro and above. Free focuses on the core link + analytics experience.
How accurate is geo and device data?
Country comes from a MaxMind GeoIP2 database and is reliable at country level for most traffic. City is a rough distribution rather than a precise count, and VPN traffic resolves to its exit node — which we flag rather than hide.
Can I bring links across from another shortener?
Yes, via CSV import: export your links, then upload a CSV with url, key, title and tags columns. A one-click Bitly importer is on the roadmap but is not built yet — the CSV route is what exists today.
Glossary
| Field | Type | Description |
|---|---|---|
| Short code / alias | term | The part after the domain that identifies a link (e.g. the 'q4-launch' in go.northlight.co/q4-launch). |
| Destination URL | term | The long URL a short link redirects to. |
| Click | term | A single resolved visit to a short link (web or QR scan), after bot filtering. |
| Unique visitor | term | A distinct person, de-duplicated within the reporting window. |
| Conversion | term | A lead or sale event attributed back to a link and customer. |
| Cloaking | term | Keeping the branded short URL in the address bar after redirect. |
| Dark social | term | Sharing that happens privately (DMs, email) and shows up as direct traffic. |
Support
We're here to help.
Pro plans include email support; Business adds priority support; Premium includes a dedicated success manager and SLA.
Ready to build?
Create a free account, grab a token, and ship your first tracked link in minutes.