← Back to LinkGenius

API Documentation

Everything you need to integrate with LinkGenius programmatically. Base URL:

Authentication

JWT Token (Dashboard)

Login or register to receive a JWT token. Include it in every request:

Authorization: Bearer <your-jwt-token>

Client ID + Client Secret (Recommended for API)

Create API credentials from the Dashboard > API Keys tab. Include both headers in every request:

X-Client-Id: lgc_xxxx...xxxx X-Client-Secret: lgs_xxxx...xxxx

The client secret is only shown once at creation time. Store it securely.

Legacy API Key

For backward compatibility, legacy API keys are also supported:

X-API-Key: lgk_xxxx...xxxx

All three methods work on all authenticated endpoints.

Rate Limits

PlanLimitWindow
Free100 requests1 hour
Pro1,000 requests1 hour
Enterprise1,000 requests1 hour

An additional global rate limit of 100 requests per 15 minutes applies to all /api/v1 routes.

Supported Platforms

Product Platforms

The product platform (platform) is auto-detected from the URL. You can also set it explicitly.

amazon custom

Marketing Platforms (SNS)

The marketing platform (marketingPlatform) is where you plan to share the link. It must be set manually.

instagram tiktok youtube facebook twitter whatsapp

Each platform auto-configures iOS/Android deep-linking schemes.

Register

POST /api/v1/auth/register Public

Create a new account. Returns a JWT token for immediate use.

Request Body

ParameterTypeDescription
emailrequiredstringEmail address
passwordrequiredstringPassword (min 6 characters)
namestringDisplay name

Response

{ "success": true, "token": "eyJhbGciOi...", "user": { "userId": "u_abc123...", "email": "[email protected]", "name": "Your Name", "plan": "free" } }

Login

POST /api/v1/auth/login Public

Authenticate with email and password. Returns a JWT token valid for 7 days.

Request Body

ParameterTypeDescription
emailrequiredstringEmail address
passwordrequiredstringPassword

Response

{ "success": true, "token": "eyJhbGciOi...", "user": { "userId", "email", "name", "plan" } }

Current User

GET /api/v1/auth/me Auth

Get the authenticated user's profile.

Response

{ "success": true, "user": { "userId", "email", "name", "plan" } }

Create API Key

POST /api/v1/api-keys Auth

Create a new API credential pair (Client ID + Client Secret). The client secret is only returned once at creation time.

Request Body

ParameterTypeRequiredDescription
namestringYesA name for this API key
descriptionstringNoOptional description

Response

{ "success": true, "message": "API key created. Save the client secret now...", "apiKey": { "client_id": "lgc_a1b2c3d4e5f6...", "client_secret": "lgs_... (only shown once)", "name": "Production", "created_at": "2025-01-01T00:00:00.000Z" } }

List API Keys

GET /api/v1/api-keys Auth

List all API keys for the authenticated user. Client secrets are never returned.

Response

{ "success": true, "apiKeys": [ { "id": 1, "client_id": "lgc_a1b2c3d4e5f6...", "name": "Production", "active": true, "revoked": false, "created_at": "2025-01-01T...", "last_used_at": null } ] }

Revoke API Key

DELETE /api/v1/api-keys/:id Auth

Revoke an API key. The key will immediately stop working for authentication.

URL Parameters

ParameterTypeRequiredDescription
idintegerYesThe API key ID

Response

{ "success": true, "message": "API key revoked successfully" }
POST /api/v1/links Auth

Create a new short link with automatic deep-linking configuration.

Request Body

ParameterTypeDescription
urlrequiredstringDestination URL
platformstringProduct platform (auto-detected from URL if omitted: amazon, custom)
marketingPlatformstringMarketing platform / SNS where the link will be shared (instagram, tiktok, youtube, facebook, twitter, whatsapp)
codestringCustom short code (4-50 chars, alphanumeric + hyphens)
titlestringLink title
descriptionstringLink description
ogTitlestringOpen Graph title (for social sharing)
ogDescriptionstringOpen Graph description
ogImagestringOpen Graph image URL
ogImageWidthnumberOpen Graph image width in pixels
ogImageHeightnumberOpen Graph image height in pixels
tagsarray | stringTags to attach to the link. Accepts either an array of strings or a comma-separated string. All tags are lowercased, trimmed, and deduplicated by the server. Empty tags are dropped. Max 25 tags per link, each up to 50 characters.
facebookPixelIdstringOptional per-link Meta Pixel ID (numeric, 6–20 digits). When set it overrides the account pixel for this link only — the redirect interstitial fires this pixel on clicks. Omit to use the account pixel; pass "" to clear.

Response

{ "success": true, "link": { "id": 42, "code": "my-link", "shortUrl": "https://yourdomain.com/my-link", "url": "https://amazon.com/dp/B0...", "platform": "amazon", "marketingPlatform": "instagram", "tags": ["summer", "sale", "electronics"], "ogImage": "https://example.com/image.jpg", "ogImageWidth": 1200, "ogImageHeight": 630, "qrCode": "https://yourdomain.com/api/qr/my-link", "createdAt": "2025-01-15T10:30:00.000Z" } }
GET /api/v1/links/:code Auth

Get a specific link by its short code. Returns click count, app opens, all metadata, and the list of tags attached to the short code.

Response

{ "success": true, "link": { "id": 42, "code": "my-link", "shortUrl": "...", "url": "...", "platform": "amazon", "marketingPlatform": "instagram", "ogImageWidth": 1200, "ogImageHeight": 630, "tags": ["summer", "sale", "electronics"], "clicks": 1542, "appOpens": 328, "active": true, "createdAt": "..." } }
GET /api/v1/links Auth

List all your links with pagination, filtering, and search.

Query Parameters

ParameterTypeDescription
limitnumberResults per page (default: 50)
offsetnumberPagination offset (default: 0)
platformstringFilter by product platform
marketingPlatformstringFilter by marketing platform (SNS)
searchstringSearch in code, title, or URL
periodstringFilter by creation date: 12h, 24h, 3d, 7d, 30d, or all (default)

Response

{ "success": true, "links": [ ... ], "pagination": { "limit": 50, "offset": 0, "total": 123 } }
PUT /api/v1/links/:code Auth

Update a link's URL, metadata, or active status. Only pass fields you want to change.

Request Body

ParameterTypeDescription
urlstringNew destination URL
titlestringNew title
descriptionstringNew description
ogTitlestringNew OG title
ogDescriptionstringNew OG description
ogImagestringNew OG image URL
ogImageWidthnumberOG image width in pixels
ogImageHeightnumberOG image height in pixels
marketingPlatformstringMarketing platform / SNS
activebooleanEnable/disable the link
tagsarray | stringReplace the link's tags. Accepts an array of strings or a comma-separated string — all tags are lowercased, trimmed, and deduplicated. Pass null or [] to clear all tags.
facebookPixelIdstringPer-link Meta Pixel ID (numeric, 6–20 digits) that overrides the account pixel for this link. Pass "" or null to clear it (link falls back to the account pixel).
DELETE /api/v1/links/:code Auth

Soft-delete a link (archives it, deactivates redirects). Cannot be undone via API.

Batch Create Links

POST /api/v1/links/batch Auth

Create up to 100 links in a single request.

Request Body

ParameterTypeDescription
linksrequiredarrayArray of link objects (max 100). Each object takes the same fields as Create Link.

Response

{ "success": true, "created": 98, "failed": 2, "links": [ ... ], "errors": [ { "index": 3, "error": "Code already exists" } ] }
GET /api/v1/links/:code/analytics Auth

Detailed analytics for a single link: devices, browsers, OS, countries, cities, referrers, clicks over time, and unique visitors.

Query Parameters

ParameterTypeDescription
startDatestringStart date filter (YYYY-MM-DD)
endDatestringEnd date filter (YYYY-MM-DD)

Response

{ "success": true, "analytics": { "totalClicks": 1542, "appOpens": 328, "uniqueVisitors": 1205, "conversionRate": 21.27, "devices": { "mobile": 890, "desktop": 552, "tablet": 100 }, "platforms": { "iOS": 450, "Android": 440, "Windows": 400 }, "browsers": { "Chrome": 800, "Safari": 500 }, "countries": { "US": 600, "GB": 200 }, "cities": [{ "city": "New York", "country": "US", "count": 150 }], "clicksOverTime": [{ "date": "2025-01-15", "clicks": 52 }], "referrers": { "google.com": 300 } } }

Dashboard Stats

GET /api/v1/dashboard/stats Auth

Aggregated stats across all your links: totals, 30-day click trend, device split, top countries, top referrers, and top/recent links.

Geography Breakdown

GET /api/v1/dashboard/geo Auth

Top 50 countries and top 50 cities across all your links.

Devices Breakdown

GET /api/v1/dashboard/devices Auth

Device types, browsers, and operating systems across all your links.

Tag Statistics

GET /api/v1/tags/stats Auth

Aggregated click statistics for one or more tags. By default, buckets are grouped by product platform (amazon, custom, …), but you can request grouping by marketing platform (whatsapp, whatsapp_channel, instagram, …) instead — or both at once. Each bucket contains average, median, max, min, clickCount, linkCount, and the list of shortCodes contributing to it. Tags are matched case-insensitively (server-side they are stored lowercased and trimmed).

Query Parameters

ParameterTypeDescription
tagsrequiredstringComma-separated list of tags (e.g. summer,sale,electronics) or repeated ?tags= params. Max 50 tags per request.
groupBystringComma-separated list of dimensions to group buckets by. Allowed values: platform, marketingPlatform. Pass multiple to get both breakdowns in the same response (e.g. groupBy=platform,marketingPlatform). Defaults to platform — omitting the parameter preserves the original response shape.
includeEventsbooleanIf true, embed all click event timestamps per short code directly in each bucket under eventsByShortCode. Expensive; prefer the dedicated click-events endpoints below for large datasets.
eventLimitnumberCap on events embedded per short code when includeEvents=true (default 1000, max 5000).

Response Shape

For every requested dimension in groupBy, the response includes a corresponding key under each tag:

DimensionResponse KeyBucket Keys Are…Missing-value Label
platformplatformsproduct platform (amazon, custom, …)unknown
marketingPlatformmarketingPlatformsmarketing platform (whatsapp, whatsapp_channel, instagram, …)none (when marketing_platform is null)

Example Request

GET /api/v1/tags/stats?tags=summer,sale&groupBy=platform,marketingPlatform Authorization: Bearer <token>

Response

{ "success": true, "requested": ["summer", "sale"], "groupBy": ["platform", "marketingPlatform"], "stats": { "summer": { "platforms": { "amazon": { "average": 412.50, "median": 380, "max": 1200, "min": 15, "clickCount": 3300, "linkCount": 8, "shortCodes": ["abc123w", "abc123wc", "def456w", "..."] } }, "marketingPlatforms": { "whatsapp": { "average": 512, "median": 480, "max": 1200, "min": 42, "clickCount": 2048, "linkCount": 4, "shortCodes": ["abc123w", "def456w", "..."] }, "whatsapp_channel": { "average": 313, "median": 280, "max": 720, "min": 15, "clickCount": 1252, "linkCount": 4, "shortCodes": ["abc123wc", "def456wc", "..."] } }, "totals": { "linkCount": 8, "clickCount": 3300, "shortCodes": ["abc123w", "abc123wc", "..."] } }, "sale": { "platforms": { ... }, "marketingPlatforms": { ... }, "totals": { ... } } }, "links": { "clickEvents": "/api/v1/links/:code/click-events", "batchClickEvents": "POST /api/v1/links/click-events/batch" } }

A short code may appear under multiple tags (if it carries more than one of the requested tags) and under multiple dimensions (a single link has both a product and a marketing platform). totals are dimension-independent and count each matching link exactly once. average and median are computed over the clicks column of the matching links within each bucket.

Click Events (single short code)

GET /api/v1/links/:code/click-events Auth

Returns click event timestamps for a single short code, along with the tags attached to it. Uses keyset pagination on the analytics row id — pass the previous response's nextCursor as cursor to fetch the next page. hasMore is false when you've reached the end.

Query Parameters

ParameterTypeDescription
limitnumberPage size (default 5000, hard max 50000).
cursornumberResume from after this id (the nextCursor from a prior response). Omit on the first page.
startDatestringOptional ISO date / datetime — only events at or after this timestamp.
endDatestringOptional ISO date / datetime — only events at or before this timestamp.

Response

{ "success": true, "shortCode": "abc123", "platform": "amazon", "tags": ["summer", "sale"], "count": 5000, "limit": 5000, "cursor": null, "nextCursor": 98421, "hasMore": true, "events": [ "2025-06-12T08:14:01.000Z", "2025-06-12T09:03:47.000Z" ] }

To fetch the next page: GET /api/v1/links/abc123/click-events?cursor=98421&limit=5000. Loop until hasMore is false.

Batch Click Events

POST /api/v1/links/click-events/batch Auth

Fetch click event timestamps for up to 100 short codes in a single request. Ideal companion to /api/v1/tags/stats: take the shortCodes arrays from the stats response and feed them in here to pull raw event timelines. Each short code is paginated independently via its own per-code cursor.

Request Body

ParameterTypeDescription
shortCodesrequiredarrayArray of short codes (max 100). Codes the caller does not own are reported under notFound.
limitnumberPer-short-code page size (default 1000, max 10000).
cursorByCodeobjectMap of { shortCode: lastId }. Each code resumes after its own id. Pass back the nextCursorByCode from the previous response to continue paging. Codes omitted from this map start from the beginning.
startDatestringOptional ISO timestamp lower bound, applied to every short code.
endDatestringOptional ISO timestamp upper bound.

Response

{ "success": true, "limit": 1000, "results": { "abc123": { "shortCode": "abc123", "platform": "amazon", "tags": ["summer", "sale"], "count": 1000, "cursor": null, "nextCursor": 42188, "hasMore": true, "events": ["2025-06-12T08:14:01.000Z", "..."] }, "def456": { "shortCode": "def456", "platform": "custom", "tags": ["sale"], "count": 0, "cursor": null, "nextCursor": null, "hasMore": false, "events": [] } }, "nextCursorByCode": { "abc123": 42188 }, "hasMore": true, "notFound": ["deleted-code"] }

Top-level hasMore is true if any code still has more events. Loop: send the previous nextCursorByCode back as cursorByCode; codes that fully drained drop out of the map and stop being queried. Once nextCursorByCode is empty, you're done.

Referral Parameter

GET /:shortCode?r=<refererId> Public

Append ?r=<refererId> to any short link to attribute the visit to a referrer (points club). When a real visitor (bots are excluded) opens the link, one access is recorded.

ParameterTypeDescription
rstringReferrer identifier (max 100 chars). Optional. Example: https://links.qchulo.com/abc123?r=user_5521

First referer wins. A given visitor IP can only ever award points to one referrer for a given short link — subsequent ?r= visits from the same IP to the same link are ignored (the first one is kept). Deduplication is permanent; it survives after accesses are retrieved and confirmed.

List Referral Accesses

GET /api/v1/referrals/accesses Auth

Returns the pending (not-yet-confirmed) referral accesses for your links, oldest first. Process the batch, then call Confirm with the highest accessId you handled so they aren't returned again.

Query Parameters

ParameterTypeDescription
limitnumberMax accesses to return (default 1000, hard max 10000).

Response

{ "success": true, "count": 2, "lastId": 4213, "accesses": [ { "accessId": 4212, "refererId": "user_5521", "accessDate": "2026-06-27T14:03:11.000Z", "ip": "203.0.113.9", "shortCode": "abc123", "marketingPlatform": "whatsapp" }, { "accessId": 4213, "refererId": "user_5521", "accessDate": "...", "ip": "198.51.100.4", "shortCode": "def456wc", "marketingPlatform": "whatsapp_channel" } ] }

Confirm Referral Accesses

POST /api/v1/referrals/accesses/confirm Auth

Marks every pending access up to and including lastId (for your links) as retrieved, so they won't be returned by List Accesses again. Accesses are not deleted — they're kept to preserve the one-referrer-per-(link, IP) guarantee permanently. Newer accesses (id > lastId) remain pending.

Request Body

ParameterTypeDescription
lastIdrequirednumberThe highest accessId you retrieved and processed (from the List response's lastId).

Response

{ "success": true, "cleared": 2 }

Typical loop: GET accesses → award points → POST confirm with the returned lastId → repeat until count is 0.

Create Team

POST /api/teams Auth

Request Body

ParameterTypeDescription
namerequiredstringTeam name

List Teams

GET /api/users/:userId/teams Auth

Returns all teams the user belongs to, including their role.

Team Members

POST /api/teams/:teamId/members Auth

Request Body

ParameterTypeDescription
userIdrequiredstringUser ID to add
rolestringRole: owner, admin, editor, viewer (default: viewer)

Folders

POST /api/teams/:teamId/folders Auth

Request Body

ParameterTypeDescription
namerequiredstringFolder name
parentIdnumberParent folder ID (for nesting)
colorstringHex color code
GET /api/teams/:teamId/folders Auth

Returns all folders for the specified team.

Activity Log

GET /api/teams/:teamId/activity Auth

Query Parameters

ParameterTypeDescription
limitnumberMax results (default: 50)

Visitor Profile

GET /api/visitors/:visitorId Auth

Returns a visitor's profile (device, language, timezone) and their full journey across your links.

Visitor Segments

GET /api/teams/:teamId/visitors/segments Auth

Query Parameters

ParameterTypeDescription
timeframenumberDays to look back (default: 30)
minVisitsnumberMinimum visit count (default: 1)

Export Visitors

GET /api/teams/:teamId/visitors/export Auth

Query Parameters

ParameterTypeDescription
formatstringcsv (default) or json
segmentstringrecent (7 days), engaged (3+ visits), or abandoned (1 visit)
POST /api/links/test Auth

Test a link's health: URL accessibility, deep-link scheme config, and fallback setup.

Request Body

ParameterTypeDescription
shortCoderequiredstringShort code to test
deviceTypestringDevice type (e.g. mobile)
osNamestringOS name (e.g. iOS)

CSV Import

POST /api/links/bulk-import Auth

Upload a CSV file to create links in bulk. Send as multipart/form-data with file field file.

CSV columns: originalUrl, platform, marketingPlatform (optional), customCode (optional), title (optional), description (optional), tags (optional)

CSV Export

GET /api/links/bulk-export Auth

Downloads all your links as a CSV file.

API Usage

GET /api/v1/usage Auth

Your API usage stats for the last 30 days.

Response

{ "success": true, "usage": { "plan": "free", "totalRequests": 542, "daysActive": 15, "endpointsUsed": 8, "totalLinks": 23 } }