Skip to content
jot.co.zm

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

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).