go-oversync

HTTP API

All /sync/* endpoints are expected to be mounted behind authentication. The handlers require an authenticated oversync.Actor{UserID, SourceID} in request context. GET /health and GET /status do not require an authenticated actor.

All visible sync keys are structured JSON objects whose values are strings on the wire. UUID-valued keys use canonical dashed lowercase UUID strings. Hidden server ownership columns such as _sync_scope_id never appear in client-visible payloads, conflicts, committed bundle rows, or snapshot rows.

All authenticated /sync/* requests must send:

POST /sync/connect

Resolve the first-connect lifecycle for the authenticated (user_id, source_id).

Request:

{
  "has_local_pending_rows": true
}

Response:

{
  "resolution": "initialize_local",
  "initialization_id": "6df0d8dd-a84b-43b6-bbca-8de70432922a",
  "lease_expires_at": "2026-03-22T12:00:00Z"
}

Possible resolution values:

Failure contract:

Notes:

POST /sync/push-sessions

Create one staging push session for a logical dirty-set bundle.

Request:

{
  "source_bundle_id": 7,
  "planned_row_count": 1
}

Response:

{
  "push_id": "6df0d8dd-a84b-43b6-bbca-8de70432922a",
  "status": "staging",
  "planned_row_count": 1,
  "next_expected_row_ordinal": 0
}

Notes:

Create failure contract:

POST /sync/push-sessions/{push_id}/chunks

Upload one contiguous chunk into a staging push session.

Request:

{
  "start_row_ordinal": 0,
  "rows": [
    {
      "schema": "business",
      "table": "users",
      "key": {"id": "550e8400-e29b-41d4-a716-446655440000"},
      "op": "INSERT",
      "base_row_version": 0,
      "payload": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "John Doe",
        "email": "john@example.com"
      }
    }
  ]
}

Response:

{
  "push_id": "6df0d8dd-a84b-43b6-bbca-8de70432922a",
  "next_expected_row_ordinal": 1
}

Failure contract:

POST /sync/push-sessions/{push_id}/commit

Commit the fully staged push session atomically.

Response:

{
  "bundle_seq": 143,
  "source_id": "source-1",
  "source_bundle_id": 7,
  "row_count": 1,
  "bundle_hash": "4c8d2d5f5d2c5a41d9aa6f4d2f3ac5d0d1d5d8bbf1d7a8c39f3b3a970f6af21a"
}

Failure contract:

Push conflict response:

{
  "error": "push_conflict",
  "message": "update conflict on business.users 550e8400-e29b-41d4-a716-446655440000: expected version 7, got 3",
  "conflict": {
    "schema": "business",
    "table": "users",
    "key": {"id": "550e8400-e29b-41d4-a716-446655440000"},
    "op": "UPDATE",
    "base_row_version": 3,
    "server_row_version": 7,
    "server_row_deleted": false,
    "server_row": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Jane Doe",
      "email": "jane@example.com"
    }
  }
}

GET /sync/committed-bundles/{bundle_seq}/rows

Fetch one deterministic page of authoritative committed rows for accepted-push replay.

Query:

Response:

{
  "bundle_seq": 143,
  "source_id": "source-1",
  "source_bundle_id": 7,
  "row_count": 1,
  "bundle_hash": "4c8d2d5f5d2c5a41d9aa6f4d2f3ac5d0d1d5d8bbf1d7a8c39f3b3a970f6af21a",
  "rows": [
    {
      "schema": "business",
      "table": "users",
      "key": {"id": "550e8400-e29b-41d4-a716-446655440000"},
      "op": "INSERT",
      "row_version": 143,
      "payload": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "name": "John Doe",
        "email": "john@example.com"
      }
    }
  ],
  "next_row_ordinal": 0,
  "has_more": false
}

DELETE /sync/push-sessions/{push_id}

Best-effort explicit cleanup for an abandoned uncommitted push session.

Response:

GET /sync/pull

Pull complete committed bundles after the client checkpoint.

Query:

Response:

{
  "stable_bundle_seq": 156,
  "bundles": [
    {
      "bundle_seq": 143,
      "source_id": "source-2",
      "source_bundle_id": 18,
      "rows": [
        {
          "schema": "business",
          "table": "users",
          "key": {"id": "550e8400-e29b-41d4-a716-446655440001"},
          "op": "INSERT",
          "row_version": 143,
          "payload": {
            "id": "550e8400-e29b-41d4-a716-446655440001",
            "name": "Jane Doe",
            "email": "jane@example.com"
          }
        }
      ]
    }
  ],
  "has_more": true
}

Notes:

Failure contract:

POST /sync/snapshot-sessions

Create one frozen snapshot session for hydration or destructive recovery.

The request body is optional.

Keep-source rebuild request:

{}

Rotated rebuild request:

{
  "source_replacement": {
    "previous_source_id": "device-old",
    "new_source_id": "device-new",
    "reason": "history_pruned"
  }
}

Notes:

Response:

{
  "snapshot_id": "2f2d3f7a-cd1f-42b9-8d08-c4d2b45d9f88",
  "snapshot_bundle_seq": 156,
  "row_count": 124,
  "byte_count": 18240,
  "expires_at": "2026-03-22T12:00:00Z"
}

Failure contract:

Structured source_retired response:

{
  "error": "source_retired",
  "message": "source device-old was retired for user user-123 and replaced by device-new",
  "source_id": "device-old",
  "replaced_by_source_id": "device-new"
}

GET /sync/snapshot-sessions/{snapshot_id}

Fetch one deterministic chunk from a frozen snapshot session.

Query:

Response:

{
  "snapshot_id": "2f2d3f7a-cd1f-42b9-8d08-c4d2b45d9f88",
  "snapshot_bundle_seq": 156,
  "rows": [
    {
      "schema": "business",
      "table": "users",
      "key": {"id": "550e8400-e29b-41d4-a716-446655440001"},
      "row_version": 143,
      "payload": {
        "id": "550e8400-e29b-41d4-a716-446655440001",
        "name": "Jane Doe",
        "email": "jane@example.com"
      }
    }
  ],
  "next_row_ordinal": 1,
  "has_more": true
}

DELETE /sync/snapshot-sessions/{snapshot_id}

Best-effort explicit cleanup for a completed or abandoned snapshot session.

Response:

GET /sync/capabilities

Returns the protocol version, schema version, app name, registered tables, registered table specs, feature flags, and bundle limits.

Important feature flags:

Important bundle limit fields:

GET /health

Readiness-oriented health response. Returns HTTP 200 when the service is healthy, and HTTP 503 when the service is unhealthy.

GET /status

Returns a lifecycle and operability snapshot including lifecycle, registered tables, feature flags, bundle visibility, retained-floor visibility, and error counters.