Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/kagisearch/kite-public/llms.txt

Use this file to discover all available pages before exploring further.

The Sync API enables Kagi News to keep user settings and article read history consistent across multiple devices. All requests are proxied server-side to https://kite.kagi.com/api/sync, so the app’s origin is used for every call — your session cookie travels with each request automatically. These are the same internal endpoints used by the official Kagi News frontend; developers building custom front-ends can use them to interoperate with the same sync infrastructure.
Every endpoint in this group requires an active Kagi account session. Unauthenticated requests will receive a 401 Unauthorized response. Make sure to include your Kagi session cookie (e.g. credentials: 'include' in fetch, or -b cookies.txt with curl) for all calls.
Custom front-ends should implement the same sync protocol to interoperate seamlessly with the official Kagi News clients. Specifically: push settings changes via POST /api/sync, pull remote state on startup via GET /api/sync, and record individual article reads via POST /api/sync/read-history-changes.

Settings Sync

GET /api/sync

Fetch the current user’s synced settings from the server. The app calls this on startup (and after re-gaining network connectivity) to pull any changes made on other devices. The response contains an array of RemoteSetting objects alongside a list of any SyncConflict entries that the server resolved on the caller’s behalf. Authentication: Required (Kagi session cookie)
settings
RemoteSetting[]
Array of synced settings. Each entry represents one persisted key/value pair.
conflicts
SyncConflict[]
Settings that had concurrent modifications across devices. The server applies a merge strategy and includes the resolved value here.
syncedAt
string
required
ISO 8601 timestamp that clients should persist as lastSyncedAt to anchor subsequent delta syncs.
curl -s \
  -b cookies.txt \
  https://kite.kagi.com/api/sync

POST /api/sync

Push local settings changes to the server. The request body should include the device identifier, the last known sync timestamp, and the list of changed settings. The server performs a three-way merge and returns the authoritative post-merge state (same SyncResponse shape as GET /api/sync). Authentication: Required (Kagi session cookie)
deviceId
string
required
A stable, unique identifier for the device or browser instance. Used by the server to detect same-device conflicts. Generate once and persist in localStorage.
lastSyncedAt
string | null
ISO 8601 timestamp of the previous successful sync, or null for a first-time push. Allows the server to perform an optimistic merge rather than a full overwrite.
settings
object[]
Array of settings changes to push. Each entry describes one key whose value has changed since lastSyncedAt.
curl -s -X POST \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "my-device-abc123",
    "lastSyncedAt": "2025-01-15T10:00:00.000Z",
    "settings": [
      {
        "key": "theme",
        "value": "dark",
        "version": 1,
        "updatedAt": "2025-01-15T10:05:00.000Z"
      },
      {
        "key": "fontSize",
        "value": "large",
        "version": 1,
        "updatedAt": "2025-01-15T10:05:01.000Z"
      }
    ]
  }' \
  https://kite.kagi.com/api/sync

Settings Export

GET /api/sync/export

Export all of the current user’s synced settings as a downloadable JSON file. Useful for backup purposes or migrating settings to a self-hosted Kagi News instance. Authentication: Required (Kagi session cookie) The response is delivered with a Content-Disposition: attachment header. The body is a JSON document containing the complete settings state at the time of export.
curl -s \
  -b cookies.txt \
  -o my-kite-settings.json \
  https://kite.kagi.com/api/sync/export

Clear Sync Data

POST /api/sync/clear

Delete all synced settings for the current user. This is a destructive, irreversible operation that wipes the server-side state. The local localStorage copy is unaffected — only the remote copy is removed. Authentication: Required (Kagi session cookie)
curl -s -X POST \
  -b cookies.txt \
  https://kite.kagi.com/api/sync/clear
POST /api/sync/clear permanently removes all server-side settings for your account. Other devices will lose their synced state the next time they pull from the server.

Read History

Read history is managed separately from settings. The app uses a change-log model: each read is recorded as an immutable add or delete operation, enabling efficient incremental (delta) sync rather than transferring the full history on every request.

GET /api/sync/read-history

Fetch the user’s complete article read history from the server. Authentication: Required (Kagi session cookie)
curl -s \
  -b cookies.txt \
  https://kite.kagi.com/api/sync/read-history

POST /api/sync/read-history

Record a single article as read on the server. Authentication: Required (Kagi session cookie)
clusterId
string
required
UUID that uniquely identifies the story cluster.
batchRunId
string
required
Identifier for the news batch in which this story appeared.
categoryId
string
UUID of the category the story belongs to.
timestamp
string
required
ISO 8601 timestamp of when the article was read.
readDuration
number
Time spent reading in seconds, if tracked.
languageCode
string
BCP 47 language code of the article (e.g. "en").
clientId
string
Idempotency key — a stable, client-generated identifier for this read event. The server uses it to prevent duplicate insertions when the same event is submitted more than once.
curl -s -X POST \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "clusterId": "550e8400-e29b-41d4-a716-446655440000",
    "batchRunId": "batch-2025-01-15-001",
    "categoryId": "cat-uuid-here",
    "timestamp": "2025-01-15T10:30:00.000Z",
    "readDuration": 45,
    "languageCode": "en",
    "clientId": "device-abc123_550e8400_2025-01-15T10:30:00.000Z"
  }' \
  https://kite.kagi.com/api/sync/read-history

DELETE /api/sync/read-history

Remove an article read entry from the server-side history. Authentication: Required (Kagi session cookie)
curl -s -X DELETE \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{"clusterId": "550e8400-e29b-41d4-a716-446655440000"}' \
  https://kite.kagi.com/api/sync/read-history

POST /api/sync/read-history-bulk

Upload multiple read history entries in a single request. Used during the initial sync when a device logs in for the first time and needs to upload its full local history. Entries are processed in chunks of up to 1,000 to avoid overloading the server. Authentication: Required (Kagi session cookie)
deviceId
string
required
Stable device identifier used for deduplication.
entries
object[]
required
Array of read history entries to upload. Each entry follows the same shape as POST /api/sync/read-history.
uploaded
number
Number of entries newly added to the server.
skipped
number
Number of entries ignored because they were already present (matched by clientId).
added
number
Synonym for uploaded returned in some response variants.
curl -s -X POST \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "my-device-abc123",
    "entries": [
      {
        "clusterId": "550e8400-e29b-41d4-a716-446655440000",
        "batchRunId": "batch-2025-01-15-001",
        "categoryId": "cat-uuid-here",
        "timestamp": "2025-01-15T09:00:00.000Z",
        "readDuration": 60,
        "languageCode": "en",
        "clientId": "bulk_550e8400_1736931600000"
      }
    ]
  }' \
  https://kite.kagi.com/api/sync/read-history-bulk

Read History Change Log

GET /api/sync/read-history-changes

Fetch incremental changes to read history since a given sequence number. This is the primary mechanism for delta sync: clients store the last seen sequence number locally and pass it back on the next poll to receive only new operations, avoiding full-history transfers. Authentication: Required (Kagi session cookie)
deviceId
string
required
The calling device’s stable identifier. The server excludes changes that originated from this device to avoid echo-back.
lastSequence
number
The sequence number from the previous successful sync. Defaults to 0 (returns all changes). Persist the lastSequence value returned in each response and pass it on subsequent calls.
success
boolean
true on a successful response.
data.changes
ReadHistoryChange[]
Ordered list of change operations since lastSequence.
data.lastSequence
number
The highest sequence number in this response. Persist this value and pass it as lastSequence on the next poll.
curl -s \
  -b cookies.txt \
  "https://kite.kagi.com/api/sync/read-history-changes?deviceId=my-device-abc123&lastSequence=42"

POST /api/sync/read-history-changes

Record one or more read/delete operations in the change log. This is the preferred method for recording reads in real time — instead of posting to /api/sync/read-history directly, the official client writes a change-log entry here so all other devices can pick it up via the GET endpoint above. Authentication: Required (Kagi session cookie)
deviceId
string
required
Stable device identifier.
operations
object[]
required
List of change-log entries to append.
curl -s -X POST \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "my-device-abc123",
    "operations": [
      {
        "operation": "add",
        "clientId": "my-device-abc123_550e8400_2025-01-15T10:30:00.000Z_x7k2m",
        "clusterId": "550e8400-e29b-41d4-a716-446655440000",
        "batchRunId": "batch-2025-01-15-001",
        "categoryId": "cat-uuid-here",
        "timestamp": "2025-01-15T10:30:00.000Z",
        "readDuration": 45,
        "languageCode": "en"
      }
    ]
  }' \
  https://kite.kagi.com/api/sync/read-history-changes

PUT /api/sync/read-history-changes

Update an existing change-log entry. Used to amend metadata (e.g. update readDuration after the user finishes reading an article that was initially opened). Authentication: Required (Kagi session cookie)
curl -s -X PUT \
  -b cookies.txt \
  -H "Content-Type: application/json" \
  -d '{
    "deviceId": "my-device-abc123",
    "operations": [
      {
        "operation": "add",
        "clientId": "my-device-abc123_550e8400_2025-01-15T10:30:00.000Z_x7k2m",
        "clusterId": "550e8400-e29b-41d4-a716-446655440000",
        "batchRunId": "batch-2025-01-15-001",
        "timestamp": "2025-01-15T10:30:00.000Z",
        "readDuration": 120
      }
    ]
  }' \
  https://kite.kagi.com/api/sync/read-history-changes

SyncState Reference

The SyncState interface describes the real-time sync status exposed to the UI. Custom front-ends can replicate this model to surface sync feedback to users.
FieldTypeDescription
isSyncingbooleantrue while a sync request is in flight.
lastSyncedAtDate | nullTimestamp of the last successful sync, or null if never synced.
pendingChangesnumberCount of local changes not yet pushed to the server.
syncErrorstring | nullError message from the most recent failed sync, or null on success.
isOnlinebooleanReflects navigator.onLine. Sync is skipped while false.
The sync manager applies exponential backoff when the server returns 429 Too Many Requests, starting at 5 seconds and doubling up to a maximum of 60 seconds.

Build docs developers (and LLMs) love