Skip to main content

Links

Everything you can do with short links, shown as REST endpoints next to the planned TypeScript SDK interface (not published yet). Requires links:read / links:write scopes.

Create​

const created = await leonai.links.create({
longUrl: 'https://example.com/spring-sale',
shortCode: 'spring-sale', // optional custom back-half (Pro+); omit for an auto code
title: 'Spring Sale',
domainId: 'dom_...', // optional — a verified custom domain you own
password: 's3cret', // Pro+ — password-protect the link
tags: ['marketing', 'q2'], // up to 10 tags, normalized (lowercased, dashed)
expiresAt: '2026-08-01T00:00:00Z', // Pro+
conversionTracking: true, // Business+ — appends ?lc_id=<clickId>
utmSource: 'newsletter',
utmMedium: 'email',
utmCampaign: 'spring',
utmTerm: 'shoes', // optional
utmContent: 'hero', // optional
});

Only longUrl is required. REST: POST /api/v1/links → 201 Created.

Field names & tier gates

The API uses shortCode for a custom back-half on create (3–50 chars, [a-zA-Z0-9_-]). Bulk import rows use customCode (see below). URLs must be http/https and up to 2048 characters. Several fields are tier-gated: a custom shortCode, password, and expiresAt require Pro+; conversionTracking requires Business+. Requesting a gated field on a lower tier returns 403.

Get by id or short code​

const link = await leonai.links.get('spring-sale');

REST: GET /api/v1/links/:id — the path segment accepts either the link id or the short code. (The /stats and analytics endpoints, by contrast, expect the link id.)

List with filtering + pagination​

const page = await leonai.links.list({
search: 'sale',
tags: ['marketing'], // matches links containing ALL given tags
limit: 50,
offset: 0,
});
console.log(page.pagination); // { total, limit, offset, hasMore }

REST: GET /api/v1/links?search=sale&tags=marketing&limit=50&offset=0

The planned SDK fetches pages transparently:

for await (const l of leonai.links.listAll({ tags: ['marketing'] })) {
console.log(l.shortUrl, l.clicks);
}

Update​

Partial updates are allowed. REST: PATCH /api/v1/links/:id.

await leonai.links.update(link.data.id, {
title: 'Spring Sale',
expiresAt: '2026-08-01T00:00:00Z',
});

Delete​

await leonai.links.delete(link.data.id);

REST: DELETE /api/v1/links/:id. The short URL stops redirecting, the cache is invalidated, and a link.deleted webhook fires.

Lifetime stats​

const { data: stats } = await leonai.links.stats(link.data.id);

Bulk import​

Import up to 1000 links per request — as JSON rows or a raw CSV string.

const bulk = await leonai.links.bulkCreate({
format: 'json',
data: [
{ longUrl: 'https://example.com/a' },
{ longUrl: 'https://example.com/b', customCode: 'b' },
],
});
console.log(bulk.data.successful, bulk.data.failed);

REST: POST /api/v1/links/bulk

Export​

Export everything as JSON (default) or a CSV string:

const json = await leonai.links.export();
const csv = await leonai.links.export({ format: 'csv' });