Overview
REST endpoints for contacts, templates, messages, media, campaigns and webhooks.
The Lynkist Public API is a JSON-over-HTTPS API. Every resource your dashboard manipulates — contacts, templates, messages, media, campaigns and the outgoing webhook subsystem itself — is reachable through this surface.
Per-resource Markdown references live in the sidebar under API Reference — each page lists the endpoints, request/response shapes, and curl examples for one resource.
The API has a machine-readable description: an OpenAPI 3.1 document for each major
version, with the exact version in info.version. Every change to it is listed in the
Changelog. A hosted interactive explorer is on the roadmap.
Base URL
https://lynkist.io/api/v1/publicEvery endpoint in these docs is relative to this base URL. For example, GET /contacts
means GET https://lynkist.io/api/v1/public/contacts.
The dashboard-only API-key management endpoints live on a separate, JWT-authenticated mount at
/{tenant}/api/v1/settings/api-keys — they are not part of the Public API and cannot be
reached with a bearer token. See Authentication.
Authentication
Every request must include an Authorization: Bearer <api_key> header. Keys look like
lk_sk_live_<40-hex> or lk_sk_test_<40-hex>. See Authentication
for scopes, rotation, and IP allowlists.
curl https://lynkist.io/api/v1/public/contacts \
-H "Authorization: Bearer $LYNKIST_API_KEY"Resources
| Resource | Path prefix | Reference |
|---|---|---|
| Contacts | /contacts | Contacts API |
| Templates | /templates | Templates API |
| Messages | /messages | Messages API |
| Media | /media | Media API |
| Campaigns | /campaigns | Campaigns API |
| Webhooks | /webhooks | Webhook management API |
Versioning
The API is versioned via URL prefix (/api/v1/public/…). Breaking changes ship as a new major
version; additive changes (new fields, new endpoints, new optional parameters) land in the
current version without notice. We aim to support each major version for at least 12 months
after its successor is announced.
Versioning
The API and the webhooks have one version, MAJOR.MINOR. The major version is in the URL
(/api/v1/public), and every response carries the exact version in the Lynkist-Version
header:
Lynkist-Version: 1.0A minor version only adds things, so a client written for 1.0 works on every 1.x. A change
that can break a client ships as a new major version, and the old one is supported for at least
12 months. Read Versioning for the full rules, and write your client
to ignore fields and values it does not know.
Pagination
Every list endpoint uses the same cursor pagination. Send limit (1–100, default 20). To
get the next page, send the next_cursor of the previous page as cursor. Lists are sorted
newest first.
curl "https://lynkist.io/api/v1/public/contacts?limit=50" \
-H "Authorization: Bearer $LYNKIST_API_KEY"{
"data": [ /* items */ ],
"pagination": {
"next_cursor": "WyIyMDI2LTA1LTEyVDA4OjAwOjAwKzAwOjAwIiwiZjQ3YWMxMGIiXQ==",
"has_more": true,
"limit": 50
}
}curl "https://lynkist.io/api/v1/public/contacts?limit=50&cursor=WyIyMDI2LTA1…" \
-H "Authorization: Bearer $LYNKIST_API_KEY"Stop when has_more is false (next_cursor is then null).
- The cursor is opaque. Do not build or change it; pass it back as you got it.
- Keep the same filters on every page of one list.
- A row that is added or removed while you page never makes the list skip or repeat a row.
- There is no total count and no page number. A cursor that is not valid answers
400 INVALID_CURSOR.
Idempotency
All POST, PUT, PATCH and DELETE requests accept an Idempotency-Key header. The first
response is cached and any retry with the same key — even a different request body — replays the
cached response.
curl -X POST https://lynkist.io/api/v1/public/messages/template \
-H "Authorization: Bearer $LYNKIST_API_KEY" \
-H "Idempotency-Key: 7c4d2e1a-…" \
-H "Content-Type: application/json" \
-d '{ "to": "+91…", "template_name": "order_confirmation", "language": "en_US" }'The cache is scoped to the bearer token (not to your tenant) and entries live for 24 hours. Use a UUID v4 per logical operation.
Request IDs
Every response — success or error — includes an X-Request-Id header. If your client sends one
on the request, we honour it; otherwise we mint a req_<12-hex> value. Log it on your side; it
is the single fastest signal we can correlate against on ours.
Rate limits
Every response carries X-RateLimit-* headers. When you exceed your plan's per-minute or
per-day budget the API returns 429 Too Many Requests with a Retry-After header. See
Rate Limits for the per-plan numbers and recommended client behaviour.
Errors
Errors are returned with a standard HTTP status and a small JSON body. See Errors for the envelope shape, status code meanings, and the typed scope- denial body.
Try it live
The Markdown reference pages in the sidebar carry copy-paste curl examples for every endpoint.
You can also import the Postman collection
(all endpoints, grouped by resource). After importing, set the collection variable api_key to
your lk_sk_live_… secret — Bearer auth and the base_url are pre-configured. Path variables
like {{contact_id}} and {{campaign_id}} are collection variables you can fill in as you go.
If you spot a discrepancy between these docs and what the API actually returns, please open an issue — the deployed behaviour is the source of truth and the docs should match.