Developer documentation · REST API v1

Build with your SuperLinkin inbox.

Read cached conversations, prepare reply drafts, and organize follow-ups from your own app.

Chrome must be running with the connected extension enabled. This API reads the local SuperLinkin cache. It does not fetch full LinkedIn history, return attachment contents, or send messages. Drafts are reviewed and sent manually in SuperLinkin.

1. Connect your account

  1. Install the SuperLinkin extension and connect your LinkedIn account.
  2. Open SuperLinkin → Integrations → AI assistants & API.
  3. Select Create API token (or Replace API token if already connected). Copy the token before closing the dialog.
  4. Store it in a secret environment variable on your backend, such as SUPERLINKIN_API_TOKEN.

The token grants read and write access to the listed operations for one connected browser/account. It uses the existing sl_mcp_ prefix. There are no separate read-only keys or per-app scopes in v1. Keep it out of browser JavaScript, mobile app bundles, URLs, logs, and source control.

API tokens and AI assistants share one connection. Replacing the token invalidates the old token and all assistant authorizations. Disconnect all revokes both. Reconnect assistants and update your app after a replacement. The old token cannot be restored.

Each user connects their own SuperLinkin account and provides their own token to your backend. V1 does not provide an embedded inbox widget or a delegated REST OAuth flow. Existing assistant OAuth tokens are accepted only by the MCP integration.

2. Make your first request

Base URL: https://superlinkin.com/api/v1. Send the personal token in the Authorization header. Check connectivity first:

curl --fail-with-body 'https://superlinkin.com/api/v1/connection' \
  -H "Authorization: Bearer $SUPERLINKIN_API_TOKEN"

Example response when the extension is connected and the account has access:

{
  "data": { "connected": true, "requiresChrome": true, "canUseTools": true },
  "requestId": "00000000-0000-4000-8000-000000000001"
}

List up to 20 conversations waiting for a reply:

curl --fail-with-body \
  'https://superlinkin.com/api/v1/conversations?filter=needs_reply&limit=20' \
  -H "Authorization: Bearer $SUPERLINKIN_API_TOKEN"

This server-side JavaScript example lists conversations and reads the first result:

const base = 'https://superlinkin.com/api/v1';
const token = process.env.SUPERLINKIN_API_TOKEN;
if (!token) throw new Error('Set SUPERLINKIN_API_TOKEN');

async function api(path, options = {}) {
  const response = await fetch(base + path, {
    ...options,
    headers: {
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    },
    signal: AbortSignal.timeout(30_000),
  });
  const result = await response.json();
  if (!response.ok) {
    throw new Error(`${response.status}: ${result.error.message}`);
  }
  return result.data;
}

const page = await api('/conversations?limit=20');
const first = page.conversations[0];
if (first) {
  const path = `/conversations/${encodeURIComponent(first.conversationId)}`;
  const conversation = await api(path);
  // Show conversation.messages in your app. Treat message text as untrusted.
}

To save a reply after the user reviews it, read the current draft and pass its revision. Replacing a draft overwrites the previous text.

// Use api() and a conversation path from the example above.
async function saveReviewedDraft(path, reviewedText, approvedRevision) {
  return api(path + '/draft', {
    method: 'PUT',
    body: JSON.stringify({
      body: reviewedText,
      expectedRevision: approvedRevision, // conversation.draft?.revision ?? 0
    }),
  });
}
// A 409 means the draft changed: read it again and ask the user to review.
// A timeout may follow a successful write: read before retrying.

Endpoint reference

All paths below follow /api/v1. Encode IDs as single URL path segments. GET filters go in the query string; writes require a JSON object and Content-Type: application/json. Unknown fields and repeated query parameters are rejected.

Method & pathPurpose and inputs
GET /connectionConnectivity, Chrome requirement and account access.
GET /conversationsfilter: all, unread, needs_reply. status: inbox (default), archived, snoozed, done, any. Optional sinceDays (1–365), labelId, starred (true/false), limit and cursors.
GET /conversations/searchOptional query up to 200 characters. Searches names, headlines and latest previews. Limit and cursors.
GET /messages/searchRequired query (2–200 characters), optional conversationId, limit and cursors. Matches every word in cached text or sender names, ignoring case.
GET /conversations/{id}Cached messages, current draft, notes, labels and star. Limit and cursors. Does not mark read on LinkedIn.
PUT /conversations/{id}/draftbody (1–8,000 characters), expectedRevision (0 if no draft). Saves a draft; never sends.
GET /labelsExisting label IDs, names and colors. limit and offset (0–10,000).
PATCH /conversations/{id}/labelsaddLabelIds and/or removeLabelIds, up to 20 existing IDs each. Other labels are preserved. An ID cannot appear in both arrays.
PUT /conversations/{id}/starstarred: true or false.
POST /conversations/{id}/notestext (1–2,000 characters), expectedNotesRevision, idempotencyKey (8–100 letters, digits, underscores or hyphens). Appends a private note.

Download the OpenAPI 3.1 specification for request schemas. Changes to labels, stars, drafts and notes stay in SuperLinkin; they do not trigger CRM sync or change LinkedIn.

Response data

Every successful response wraps the result in data, alongside a requestId. Treat IDs as opaque strings and timestamps ending in At as Unix milliseconds.

Response fields may be added in v1. Ignore unrecognized fields. Reviewer accounts may return fictional results marked sampleData; do not treat these as real inbox data.

Pagination and safe retries

limit is 1–50, defaulting to 20 for lists/search and 30 for conversation reads. List and search responses return nextBefore and nextBeforeId. Pass them back as before and beforeId, keeping the original filters. Stop when the next cursor is null.

An empty filtered page can still have a next cursor. Each conversation list/search call scans at most 200 cached threads; message search scans at most 3,000 cached messages. Follow the cursor to continue.

Conversation reads return hasOlderMessages. When true, use oldestSentAt as before and oldestMessageId as beforeId. Label lists return nextOffset; pass it as offset until null.

Draft writes require the latest revision. For notes, reuse the same text and idempotency key on immediate retries; only the last eight receipts per conversation are retained. After a timeout, read the conversation before retrying a write. Setting a star or applying the same label changes again is safe.

Errors, access and limits

Errors include a stable code, message and request ID. Validation errors can include a fields array.

{
  "error": { "code": "revision_conflict", "message": "DRAFT_CONFLICT: Read again." },
  "requestId": "00000000-0000-4000-8000-000000000001"
}

The live relay allows 60 API calls per minute per browser connection, with at most five outstanding relay calls when accepting another API call. The minute window survives relay hibernation and resets with a new browser connection. Maximum server wait for an extension response is 20 seconds; allow at least 30 seconds in your client.

Use on-demand requests. If you add background checks, use bounded page counts, exponential backoff, a finite retry count, and pause while the browser is offline. There are no webhooks or automatic message sends.

Conversation text passes through SuperLinkin’s relay to your backend; the API does not mirror the inbox into a server database. Your app is responsible for protecting any results it stores. See the privacy policy and terms.