Skip to content
nikcli
Docs
Documentation

Sync

Event-sourced sync: push events, read the outbox and snapshots, stream changes, and manage the connection and drain.

Playground

Send these requests to your own running server. Values stay in this browser.

Not connected
How this works

Start a server with nikcli serve --hostname 127.0.0.1 --port 4096. Requests go straight from this page to that address — the browser allows it because loopback counts as a secure origin, and the server allows it because nikcli-ai.dev is in its CORS allowlist.

To try things without touching your real sessions or config, start the server with NIKCLI_TEST_HOME pointed at a throwaway directory — see the guided tour.

Operations

9 endpoints, generated from the server's own OpenAPI document. Every path also accepts the directory and workspace query parameters that select which instance handles the request.

post /sync/event sync.event.push
get /sync/outbox sync.outbox.list
get /sync/snapshot/{aggregateID} sync.snapshot.get
get /sync/stream sync.event.stream
get /sync/stats sync.stats
post /sync/config sync.config.set
post /sync/connect sync.connect
post /sync/disconnect sync.disconnect
post /sync/drain sync.drain
post /sync/event # sync.event.push
Parameters
Name In Type Required
directory query string optional
workspace query string optional
Request body · required · application/json
{
  event: SyncEventRecord
  projectID: string
}
Responses
204 <No Content>
401 UnauthorizedChallenge
429 SyncRateLimited
SDK example
sync.event.push
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.event.push({
  ...
})
Try it
get /sync/outbox # sync.outbox.list
Parameters
Name In Type Required
projectID query string required
since query string | null optional
afterAggregate query string | null optional
afterID query string | null optional
directory query string optional
workspace query string optional
Responses
200 SyncOutboxResponse application/json
{
  events: unknown[]
  hasMore: boolean
  nextCursor?: 
    | {
    seq: number
    aggregate: string
    id: string
  }
    | null
}
Example response from schema
{
  "events": [],
  "hasMore": false,
  "nextCursor": {
    "seq": 0,
    "aggregate": "",
    "id": ""
  }
}

Generated from the response schema — field values are placeholders, the shape is real.

SDK example
sync.outbox.list
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.outbox.list({
  ...
})
Try it
get /sync/snapshot/{aggregateID} # sync.snapshot.get
Parameters
Name In Type Required
aggregateID path string required
projectID query string required
directory query string optional
workspace query string optional
Responses
200 SyncSnapshotResponse application/json
{
  lastSeq: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  state: unknown
}
Example response from schema
{
  "lastSeq": 0,
  "state": null
}

Generated from the response schema — field values are placeholders, the shape is real.

SDK example
sync.snapshot.get
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.snapshot.get({
  ...
})
Try it
get /sync/stream # sync.event.stream
Parameters
Name In Type Required
projectID query string required
readiness query string | null optional
token query string required
directory query string optional
workspace query string optional
Responses
200 Success text/event-stream
{
  id: string | null
  event: string
  data: string
}
Example response from schema
{
  "id": "",
  "event": "",
  "data": ""
}

Generated from the response schema — field values are placeholders, the shape is real.

SDK example
sync.event.stream
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.event.stream({
  ...
})
Try it
get /sync/stats # sync.stats
Parameters
Name In Type Required
projectID query string | null optional
directory query string optional
workspace query string optional
Responses
200 SyncStatsOutput application/json
{
  url?: string | null
  configured: boolean
  source: string
  connected: boolean
  pending: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  failed: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  total: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  lastSeq: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  lastError?: string | null
  lastChange: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  events: SyncStatsEvent[]
}
Example response from schema
{
  "url": "",
  "configured": false,
  "source": "",
  "connected": false,
  "pending": 0,
  "failed": 0,
  "total": 0,
  "lastSeq": 0,
  "lastError": "",
  "lastChange": 0,
  "events": [
    {
      "id": "",
      "projectId": "",
      "workspaceId": "",
      "aggregate": "",
      "seq": 0,
      "type": "",
      "timestamp": 0,
      "origin": "",
      "dataPreview": null
    }
  ]
}

Generated from the response schema — field values are placeholders, the shape is real.

SDK example
sync.stats
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.stats({
  ...
})
Try it
post /sync/config # sync.config.set
Parameters
Name In Type Required
directory query string optional
workspace query string optional
Request body · required · application/json
{
  url: string
  // Omit to keep the token already saved in the config file
  token?: string | null
  autostart?: boolean | null
}
Responses
200 SyncConfigSetResponse application/json
{
  configured: boolean
  url?: string | null
  source?: "env" | "config" | null
  started: boolean
  error?: string | null
}
Example response from schema
{
  "configured": false,
  "url": "",
  "source": "env",
  "started": false,
  "error": ""
}

Generated from the response schema — field values are placeholders, the shape is real.

SDK example
sync.config.set
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.config.set({
  ...
})
Try it
post /sync/connect # sync.connect
Parameters
Name In Type Required
directory query string optional
workspace query string optional
Responses
204 <No Content>
SDK example
sync.connect
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.connect({
  ...
})
Try it
post /sync/disconnect # sync.disconnect
Parameters
Name In Type Required
directory query string optional
workspace query string optional
Responses
204 <No Content>
SDK example
sync.disconnect
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.disconnect({
  ...
})
Try it
post /sync/drain # sync.drain
Parameters
Name In Type Required
directory query string optional
workspace query string optional
Responses
204 <No Content>
SDK example
sync.drain
ts
import { createNikcliClient } from "@nikcli-ai/sdk/httpapi"

const client = createNikcliClient()
await client.sync.drain({
  ...
})
Try it

Schemas

The 8 schemas reachable from these endpoints. Each is shown one level deep; nested types link to their own entry below. Names ending in _2, _3 and so on are the OpenAPI emitter disambiguating same-named schemas declared by different HttpApi groups — they are distinct shapes, not duplicates.

SyncConfigSetInput
{
  url: string
  // Omit to keep the token already saved in the config file
  token?: string | null
  autostart?: boolean | null
}
SyncConfigSetResponse
{
  configured: boolean
  url?: string | null
  source?: "env" | "config" | null
  started: boolean
  error?: string | null
}
SyncEventPushInput
{
  event: SyncEventRecord
  projectID: string
}
SyncEventRecord
{
  id: string
  projectId: string
  workspaceId?: string | null
  aggregate: string
  seq: number
  type: string
  data: unknown
  timestamp: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  origin?: string | null
  originSeq?: 
    | 
    | number
    | "Infinity" | "-Infinity" | "NaN"
    | null
}
SyncOutboxResponse
{
  events: unknown[]
  hasMore: boolean
  nextCursor?: 
    | {
    seq: number
    aggregate: string
    id: string
  }
    | null
}
SyncSnapshotResponse
{
  lastSeq: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  state: unknown
}
SyncStatsEvent
{
  id: string
  projectId: string
  workspaceId?: string | null
  aggregate: string
  seq: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  type: string
  timestamp: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  origin: string
  dataPreview: unknown
}
SyncStatsOutput
{
  url?: string | null
  configured: boolean
  source: string
  connected: boolean
  pending: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  failed: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  total: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  lastSeq: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  lastError?: string | null
  lastChange: 
    | number
    | "Infinity" | "-Infinity" | "NaN"
  events: SyncStatsEvent[]
}