Lynkist Developers

Authentication

API keys, scopes, IP allowlists, and rotation for the Lynkist Public API.

The Lynkist Public API uses bearer-token authentication. Every request must include an Authorization: Bearer <api_key> header.

API key format

API keys always have four underscore-separated parts:

lk_sk_<env>_<40-character-hex-secret>
       │     │
       │     └── 40 random hex characters
       └── live | test
TypePrefixUse
Livelk_sk_live_…Production traffic
Sandboxlk_sk_test_…Local development, CI, integration tests

Live and sandbox keys hit the same base URL — what changes is only the prefix on the key itself.

Treat API keys like passwords. Do not commit them to source control, ship them in client-side bundles, log them, or paste them into chat. Store them in environment variables or a secrets manager.

Creating a key

API key creation is dashboard-only (JWT-authenticated). The Public API itself cannot mint keys.

  1. In the dashboard, open Settings → API keys. The mount is /{tenant}/api/v1/settings/api-keys.
  2. Click Create new key.
  3. Pick a name (visible to your team), the environment (live or test) and one or more scopes (see Scopes below).
  4. Copy the secret immediately — it is shown once and never again.

The response contains the metadata plus the plain-text secret:

{
  "api_key": {
    "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "name": "Server-side messaging",
    "key_prefix": "lk_sk_live_",
    "scopes": ["messages:send", "templates:read"],
    "environment": "live",
    "is_active": true,
    "created_at": "2026-05-31T08:00:00Z",
    "last_used_at": null
  },
  "secret": "lk_sk_live_a1b2c3d4…"
}

Only the key_prefix (the first 12 characters) is stored on Lynkist's side after creation; the secret is irrecoverable. If you lose it, rotate the key.

Making authenticated requests

Pass the secret in the Authorization header.

curl https://api.lynkist.io/api/v1/public/contacts \
  -H "Authorization: Bearer lk_sk_live_..."

If the key is missing, invalid, expired, or revoked, the API returns 401 Unauthorized. If the key is valid but lacks the scope for the route, you get 403 Forbidden — see Errors for the response shape.

Scopes

A key carries a list of resource:action strings. Lynkist enforces the relevant scope on every endpoint; a request missing the required scope is rejected with 403. The wildcard scope * satisfies every check.

Full catalogue (12 scopes):

ScopeAllows
contacts:readList, search, get contacts
contacts:writeCreate, update, bulk-create, archive contacts
templates:readList, get approved templates
templates:writeCreate and submit templates for approval
messages:sendSend template messages
media:readList, get media
media:writeUpload media, create resumable upload sessions, delete media
webhooks:readList endpoints, list deliveries, view metrics
webhooks:writeCreate / update / delete endpoints, rotate secret, retry, send tests
campaigns:readList, get, preview, metrics, errors
campaigns:writeCreate, set audience, render preview, refresh metrics
campaigns:sendSend, schedule, pause, resume, stop

Presets

When creating a key in the dashboard you can pick one of four presets instead of hand-selecting scopes:

PresetScopes
read_onlycontacts:read, templates:read, media:read, webhooks:read, campaigns:read
messagingcontacts:read, templates:read, media:write, messages:send
campaignscontacts:read, templates:read, media:read, campaigns:read, campaigns:write, campaigns:send
full_access* (wildcard — every scope, current and future)

Scope-denial response

When a key is missing a required scope, the response body explicitly lists what was required versus what was held — useful for surfacing "you need to ask your admin for X" prompts inside integrations:

{
  "detail": {
    "message": "Missing required scope(s): campaigns:send",
    "required_permissions": ["campaigns:send"],
    "current_permissions": ["campaigns:read", "campaigns:write"]
  }
}

IP allowlists

A key can optionally be locked to a set of source IPs or CIDR ranges. Requests from any other address return 403 Request IP not in allowlist, even if the key and scopes are otherwise valid. Configure the allowlist in the dashboard when creating the key.

Allowlist entries can be either plain IPs (203.0.113.7) or CIDR (203.0.113.0/24).

Use this for tightly-scoped server-side keys — never for keys that legitimately roam (e.g. a laptop on a hotel network).

Rotating a key

  1. From the dashboard, click Rotate on the existing key. Lynkist mints a new secret with the same scopes and environment and returns it once.
  2. Deploy the new secret to every service that uses it.
  3. The old key is revoked immediately as part of the rotate operation — there is no grace period.

The rotate endpoint is POST /{tenant}/api/v1/settings/api-keys/{key_id}/rotate. Plain revoke (without minting a replacement) is POST .../revoke.

Best practices

  • Separate live and sandbox keys. Sandbox in dev/CI, live only in production. Pre-prod smoke tests should use a sandbox key.
  • One key per service. Issue a distinct key for each downstream service so you can revoke one without taking another offline.
  • Minimum scopes. A campaign-only service does not need messages:send. Start narrow.
  • IP-lock long-lived keys. Anything running on a known set of servers should be allowlisted.
  • Watch last_used_at. The dashboard shows it on every key. Revoke anything idle for 90+ days.
  • Pair with Idempotency-Key. See API Reference for safe-retry semantics.

OAuth-style delegated access (for building third-party integrations against multiple tenants) is not available yet. Today, all programmatic access is via per-tenant bearer keys.

Authentication — Lynkist Developers | Lynkist