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.
A hosted, public-API-only interactive explorer (filtered OpenAPI sub-app + Swagger UI) is on
the roadmap. We intentionally do not expose the raw FastAPI /docs in production — the
process hosts internal, dashboard and public routers behind a single OpenAPI document, and we
don't want internal routes enumerable from the public internet. Track Changelog
for the public explorer's ship date.
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.
Pagination
The Contacts and Templates list endpoints use offset pagination: pass ?page= and
?limit= (limit is capped at 100). The Media, Campaigns, and Webhooks list
endpoints are not paginated — they return the full set as { "data": [ … ] } with no
pagination envelope. Each per-resource reference says which behaviour applies.
curl "https://lynkist.io/api/v1/public/contacts?page=2&limit=50" \
-H "Authorization: Bearer $LYNKIST_API_KEY"Every paginated response wraps the items under data and exposes a pagination envelope:
{
"data": [ /* items */ ],
"pagination": {
"page": 2,
"limit": 50,
"total_items": 134,
"total_pages": 3,
"has_next": true,
"has_prev": true
}
}Stop paging when has_next is false.
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.