Basics
- Base URL:
https://app.keptlink.com/api/v1 - Authentication: send
Authorization: Bearer <API key>. Owners and admins create keys in the dashboard under Workspace settings → API keys. A key is shown once, works for its own workspace only, and can do what an editor can (never billing or members). Revoking a key stops it on the next request. - Quota: every call counts toward the plan's rolling 24-hour API quota. Over the quota, the API answers
429with aRetry-Afterheader (seconds). Usage is shown under Workspace settings → Usage. - Changes: a new destination is safety-checked like one entered in the dashboard and reaches visitors within about a minute or two. Updates need the link's current
version(expected_version), so two programs can't overwrite each other. - Format: JSON in and out, field names in
snake_case, times in ISO 8601 (UTC). - Errors:
{ "error": { "code": "…", "message": "…" } }with the HTTP status: 400 invalid request, 401 missing or invalid key, 403 not allowed (plan, read-only workspace, blocked link), 404 not found in this workspace, 409 version conflict or code taken, 429 over quota.
Example
curl https://app.keptlink.com/api/v1/links \
-H "Authorization: Bearer $KEPTLINK_API_KEY" \
-H "Content-Type: application/json" \
-d '{"destination": "https://example.com/menu", "title": "Menu"}'Endpoints
POST /links— Create a linkGET /links— List linksGET /links/{id}— Get a linkPATCH /links/{id}— Update a linkPOST /links/{id}/archive— Archive a linkGET /links/{id}/analytics/summary— Visit totals for a link
POST /links
Create a link.
Request body
destination(string, required): The http(s) URL visitors are sent to. Max 4096 characters.code(string): A custom back-half (plans with custom back-halves). Random if omitted. Max 64 characters.domain_id(string): An active custom domain of the workspace. Default: keptlink.app. Max 64 characters.title(string or null): A label for you.tags(array of string): Max 10 items.utm(object): UTM parameters added to the destination when a visitor is redirected.forward_query(boolean): Pass the short link's query string on to the destination.
Responses: 201 Created · 400 Invalid request (error.code says why, e.g. invalid_destination) · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 404 Not found in this workspace · 409 Version conflict or code taken · 429 Over the plan's rolling 24-hour API quota
GET /links
List links.
Parameters
status(query, "active" | "archived"): Default "active".limit(query, integer): Min 1, max 100, default 50.cursor(query, string)
Responses: 200 A page of links · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 429 Over the plan's rolling 24-hour API quota
GET /links/{id}
Get a link.
Parameters
id(path, string, required)
Responses: 200 The link · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 404 Not found in this workspace · 429 Over the plan's rolling 24-hour API quota
PATCH /links/{id}
Update a link.
Parameters
id(path, string, required)
Request body
expected_version(integer, required): The link's current version. A different version gets a 409.destination(string): Max 4096 characters.title(string or null): A label for you.tags(array of string): Max 10 items.utm(object): UTM parameters added to the destination when a visitor is redirected.forward_query(boolean): Pass the short link's query string on to the destination.
Responses: 200 Updated · 400 Invalid request (error.code says why, e.g. invalid_destination) · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 404 Not found in this workspace · 409 Version conflict or code taken · 429 Over the plan's rolling 24-hour API quota
POST /links/{id}/archive
Archive a link. An archived link stops redirecting (visitors see a 'link no longer active' page).
Parameters
id(path, string, required)
Request body
expected_version(integer)
Responses: 200 Archived · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 404 Not found in this workspace · 409 Version conflict or code taken · 429 Over the plan's rolling 24-hour API quota
GET /links/{id}/analytics/summary
Visit totals for a link.
Parameters
id(path, string, required)days(query, integer): Min 1, default 30.from(query, string)to(query, string)
Responses: 200 Totals · 400 Invalid request (error.code says why, e.g. invalid_destination) · 401 The API key is missing, invalid or revoked · 403 Not allowed: plan, read-only workspace, or blocked link · 404 Not found in this workspace · 429 Over the plan's rolling 24-hour API quota
The link object
id(string)code(string)hostname(string)short_url(string)qr_url(string): The URL encoded in the link's QR code.destination_url(string)pending_destination_url(string or null): A new destination still being safety-checked.title(string or null)tags(array of string)utm(object)forward_query(boolean)status("active" | "archived")serve(object): What a visitor gets right now: a redirect, a safety check in progress, a paused, blocked or gone page.safety_status(string)permanent(boolean): Keeps redirecting after a cancellation.version(integer)created_at(string): ISO 8601.updated_at(string)archived_at(string or null)
The machine-readable OpenAPI 3.1 document is at https://app.keptlink.com/api/v1/openapi.json.