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.
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
Iterate every matching link
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' });
Related
- Analytics — clicks and conversions per link
- QR codes — a scannable image for any link
- Smart routing — geo/device/time/A-B rules