Skip to content
LinkProfit

Developer API

A REST API that covers everything the dashboard does

Create links, read analytics, connect domains and manage client workspaces over HTTP with a bearer key. The API is generated from the same validation schemas the product uses, published as OpenAPI, and frozen at version one — breaking changes only ever arrive as a new version.

Redirects served from the location closest to the click

Two key scopes, because there are two kinds of caller

A workspace key acts inside one workspace: links, analytics, domains available to it, and its own usage. A partner key acts across the business: clients and their subscriptions, the plans you sell, all domains, payments with their fee breakdown, payouts and an aggregated analytics overview. The two prefixes are visibly different, so a key pasted into the wrong service fails immediately instead of doing something surprising.

Keys are created in the dashboard, shown once and stored only as a hash. Each key carries its own scope list, so an integration that only needs to read analytics can be issued a key that cannot create or delete anything. Keys can be given an expiry date and revoked instantly, and the last time each key was used is displayed, which is how you find the integration nobody remembers setting up.

  • POST /links, GET /links, GET /links/{id}, PATCH /links/{id}, DELETE /links/{id}
  • POST /links/bulk — up to a hundred links per call
  • GET /links/{id}/qr — PNG or SVG, with a preset and a size
  • GET /analytics/summary, /timeseries, /breakdown, /links/top, /export.csv
  • GET and POST /domains — connect a domain and read the DNS records it needs
  • GET /workspace — plan limits and current usage
  • GET /partner/clients, /partner/plans, /partner/payments, /partner/payouts

Predictable in the ways that matter at three in the morning

Every error is the same shape — a code, a human-readable message and a documentation URL — so a client library can branch on the code and a human can read the message. Lists are paginated with cursors rather than page numbers, which keeps results stable while links are being created underneath you.

Rate limits default to six hundred requests per minute on a workspace key and twice that on a partner key, with the limit, the remaining count and the reset time returned as headers on every response. Exceeding them returns 429 with a Retry-After header rather than a connection reset, so well-behaved clients back off correctly. Analytics exports stream, so a hundred thousand rows do not require holding a report in memory on either side.

Webhooks for the events you would otherwise poll for

Register an endpoint and receive link creation, updates and deletions; domain lifecycle events as a hostname moves from pending SSL to active or into an error state; and, on partner keys, client subscription and payment events. Polling a domain status endpoint once a minute is exactly the kind of code nobody should be writing.

Every delivery carries a timestamped HMAC-SHA256 signature header so your receiver can verify the payload came from us and is not a replay. Failed deliveries are retried five times with growing gaps — one minute, five, thirty, two hours, twelve — after which the endpoint is marked failing and an email goes out. A test event can be sent from the dashboard, so the integration is verifiable before anything real depends on it.

Documentation generated from the code that runs

The OpenAPI specification is built from the same schemas the API validates against, which means it cannot drift from the implementation the way a hand-written reference does. It is published as a file you can feed to a client generator and rendered as browsable reference documentation on this site, alongside hand-written guides for the quickstart, pagination, errors, webhooks and rate limits.

Version one is frozen. New fields may be added, existing behaviour will not change, and anything that would break a caller waits for a version two at a different path. If you are choosing a shortener to build on rather than to use, that promise is worth more than any individual endpoint.

Code that speaks for itself

Create a link — curl
curl -X POST https://api.linkprofit.com/v1/links \
  -H 'Authorization: Bearer lp_live_XXXXXXXX' \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com/spring-collection",
    "domain_id": "dom_8kq2vn41",
    "slug": "spring",
    "title": "Spring collection",
    "utm": {
      "utm_source": "newsletter",
      "utm_medium": "email",
      "utm_campaign": "spring-2026"
    }
  }'
Create a link — JavaScript fetch
const response = await fetch("https://api.linkprofit.com/v1/links", {
  method: "POST",
  headers: {
    Authorization: "Bearer lp_live_XXXXXXXX",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://example.com/spring-collection",
    domain_id: "dom_8kq2vn41",
    slug: "spring",
  }),
});

if (!response.ok) {
  const { error } = await response.json();
  throw new Error(error.code + ": " + error.message);
}

const link = await response.json();
console.log(link, response.headers.get("X-RateLimit-Remaining"));
Create a link — Python requests
import requests

response = requests.post(
    "https://api.linkprofit.com/v1/links",
    headers={"Authorization": "Bearer lp_live_XXXXXXXX"},
    json={
        "url": "https://example.com/spring-collection",
        "domain_id": "dom_8kq2vn41",
        "slug": "spring",
    },
    timeout=10,
)

if response.status_code == 429:
    raise SystemExit("rate limited, retry after " + response.headers["Retry-After"])

response.raise_for_status()
print(response.json())

Frequently asked questions

Which plans include API access?

For partners, API access starts with the Growth plan and is included in everything above it. For your own clients, you decide: API access is one of the switches on each plan you create, so it can be a premium tier of your service or included everywhere.

Can the API run on my own hostname?

Not in version one. The API is served from api.linkprofit.com, and partners document it to their clients as the API of their service. Everything a client sees in the browser — dashboard, links, emails, checkout — is on your domains; the API hostname is the one honest exception.

Is there a sandbox for testing?

Use a dedicated workspace and a key scoped to it. Links created there resolve on a real domain and produce real analytics, which is more useful than a simulated environment when you are verifying that redirects, targeting and webhooks behave as documented.

Launch your branded link shortener

Connect a domain, publish your prices and invite your first customer — most partners go live in an evening.

No card required for the trial.