API reference
Every Jot v1 API endpoint in one place — request and response shapes, authentication, rate limits, and error codes.
Hand-written against the live API — not generated yet (a proper OpenAPI spec is on the way). See Getting started for authentication and a first call; see Links, Webhooks, Rate limits, and Errors for the narrative version of everything below.
Auth & rate limits
Authorization: Bearer jot_live_<key> on every request. Each key is
scoped read and/or write — a route marked write below 403s a
read-only key. Requests are rate-limited per key (req/s scales with your
plan: Free 2, Plus 5, Team 10, Business/Enterprise 50), with
X-RateLimit-Remaining/X-RateLimit-Limit headers on every response
and a 429 plus Retry-After once exceeded. Bulk-create has its own
separate, higher ceiling.
Errors are always JSON: { "error": "<message>" }, occasionally with
extra fields (e.g. quota errors include remaining).
POST /v1/links — write
Create a link.
{
"destinationUrl": "https://example.com/launch", // required, http(s)
"customBackHalf": "launch-2026" // optional, 3-30 chars [A-Za-z0-9_-]
}
{
"shortUrl": "https://jot.co.zm/aB3xQ",
"shortCode": "aB3xQ",
"destinationUrl": "https://example.com/launch",
"expiresAt": null,
"qrUrl": "https://jot.co.zm/api/qr/aB3xQ.svg"
}
Errors: 400 invalid URL or back-half · 409 back-half already taken · 422 monthly link quota exceeded
GET /v1/links — read
List your links, newest first. Query: ?cursor=<opaque> (optional, from a previous response's nextCursor).
{ "links": [ { "id", "shortCode", "destinationUrl", "isActive", "createdAt", "..." } ], "nextCursor": "... | null" }
POST /v1/links/bulk — write
Create up to 5,000 links in one call. One bad item fails only that item, not the batch.
{ "items": [ { "destinationUrl": "..." }, { "destinationUrl": "...", "customBackHalf": "..." } ] }
{
"results": [
{ "status": "created", "index": 0, "shortUrl": "...", "shortCode": "...", "destinationUrl": "..." },
{ "status": "failed", "index": 1, "destinationUrl": "...", "code": "back_half_taken", "error": "..." }
],
"createdCount": 1,
"failedCount": 1
}
Errors: 400 batch exceeds your plan's per-request cap · 403 bulk-create requires the Plus plan or above
GET /v1/links/:id — read
Get one link by id.
200 OK — the full link record (id, shortCode, destinationUrl, isActive, expiresAt, createdAt, updatedAt, ...).
Errors: 404 not found (also returned if the link belongs to a different org — never 403, to avoid confirming another org's link ids exist)
PATCH /v1/links/:id — write
Change a link's destination.
{ "destinationUrl": "https://example.com/new-target" }
204 No Content. Errors: 400 invalid URL · 404 not found
DELETE /v1/links/:id — write
Deactivate a link (soft delete — the short code stops redirecting).
204 No Content. Errors: 404 not found
POST /v1/webhooks — write
Register a webhook. Requires the Team plan or above.
{ "targetUrl": "https://example.com/hook", "eventTypes": ["link.created"] }
targetUrl must be https://.
{ "id", "targetUrl", "eventTypes": ["link.created"], "signingSecret": "whsec_...", "isActive": true, "createdAt", "updatedAt" }
signingSecret is shown in full here only — store it, it's used to verify delivery signatures.
Errors: 403 webhooks require the Team plan or above
GET /v1/webhooks — read
List your webhook subscriptions.
{ "subscriptions": [ { "id", "targetUrl", "eventTypes", "isActive", "createdAt" } ] }
DELETE /v1/webhooks/:id — write
Remove a webhook subscription.
204 No Content. Errors: 404 webhook subscription not found
GET /v1/usage — read
This billing period's link count, quota and clicks.
{ "periodStart": 1759276800, "linksCreated": 42, "linksQuota": 150, "clicks": 318, "plan": "free" }
clicks counts people only (see What counts as a click).
It's null if click data is briefly unavailable; the link count and quota are always present.
linksQuota is null on Enterprise (no cap).