Electric HTTP Sync API

The core HTTP API that syncs Shapes of Postgres data to clients. Clients issue GET /v1/shape requests with table and offset parameters to receive shape log entries as newline-delimited JSON; a live=true flag enables long-polling and live_sse=true switches to Server-Sent Events for real-time streaming. Authentication is handled via the ELECTRIC_SECRET token or a backend proxy pattern.

OpenAPI Specification

electric-sql-http-sync-api-openapi.yml Raw ↑
openapi: 3.1.0

info:
  title: Electric HTTP API
  description: |-
    [HTTP API](https://electric-sql.com/docs/sync/api/http) to sync
    partial replicas of your Postgres data into local apps
    and services.

    See the [Electric documentation](https://electric-sql.com/docs/sync/)
    for more information.
  version: __PLACEHOLDER_SYNC_SERVICE_VERSION__

servers:
  - url: http://localhost:3000
    description: Local server

components:
  parameters:
    secret:
      name: secret
      in: query
      schema:
        type: string
      example: 1U6ItbhoQb4kGUU5wXBLbxvNf
      description: |-
        Secret defined by the [ELECTRIC_SECRET](https://electric-sql.com/docs/api/config#electric-secret)
        configuration variable. This is required unless
        `ELECTRIC_INSECURE` is set to `true`. More details are
        available in the [security guide](https://electric-sql.com/docs/guides/security).
    api_secret:
      name: api_secret
      in: query
      schema:
        type: string
      example: 1U6ItbhoQb4kGUU5wXBLbxvNf
      deprecated: true
      description: |-
        Deprecated in favor of the `secret` query parameter.
        Will be removed in v2.

paths:
  /v1/shape:
    get:
      summary: Get Shape
      description: |-
        Load the initial data for a shape and poll for real-time updates.

        Define your shape using the `table` and `where` parameters.
        Use `offset` to fetch data from a specific position in the shape
        log and the `live` parameter to consume real-time updates.
      parameters:
        # Query parameters
        - name: table
          in: query
          schema:
            type: string
          examples:
            simple:
              value: issues
              summary: the issues table in the public schema
            qualified:
              value: foo.issues
              summary: the issues table in the foo schema
          required: true
          description: |-
            Root table of the shape. Must match a table in your Postgres database.

            Can be just a tablename, or can be prefixed by the database schema
            using a `.` delimiter, such as `foo.issues`. If you don't provide
            a schema prefix, then the table is assumed to be in the `public.` schema.
        - name: offset
          in: query
          schema:
            type: string
          examples:
            initial_sync:
              value: '-1'
              summary: sync the shape from the start
            ongoing_sync:
              value: '26800584_4'
              summary: continue syncing from offset `26800584_4`
            skip_historical:
              value: 'now'
              summary: skip all historical data and start from the current point
          required: true
          description: |-
            The offset in the shape stream. This is like a cursor that specifies
            the position in the shape log to request data from.

            When making an initial request to sync a shape from scratch, you
            **must** set the `offset` to `-1`. Then, when continuing to
            sync data, you should set the `offset` to the last offset you have
            already received, to continue syncing new data from that position
            in the stream.

            Alternatively, you can set `offset` to `now` to skip all historical
            data and receive an immediate up-to-date message with the latest
            continuation offset. This is useful when combined with `log=changes_only`
            mode and `replica=full` for applications that don't need historical data.

            Note that when `offset` is not `-1` or `now` then you must also provide
            the shape's `handle`.
        - name: live
          in: query
          schema:
            type: boolean
          description: |-
            Whether to wait for live updates or not.

            When the `live` parameter is omitted or set to `false`, the server
            will always return immediately, with any data it has, followed by an
            up-to-date message.

            Once you're up-to-date, you should set the `live` parameter to `true`.
            This puts the server into live mode, where it will hold open the
            connection, waiting for new data arrive.

            This allows you to implement a long-polling strategy to consume
            real-time updates.
        - name: live_sse
          in: query
          schema:
            type: boolean
          description: |-
            Use Server-Sent Events (SSE) for live updates instead of long polling.

            When set to `true` along with `live=true`, the server will use SSE
            to stream updates to the client. SSE provides a persistent connection
            that allows the server to push updates as they happen, which is more
            efficient than long polling.

            SSE messages are sent in the standard SSE format with `data:` prefixes.
            The stream includes data messages (shape log entries), control messages
            (up-to-date, must-refetch, etc.), and keep-alive comments sent every
            21 seconds to prevent connection timeout.

            **Important**: SSE requires that reverse proxies and CDNs support
            streaming responses without buffering. Configure your proxy accordingly:
            - Nginx: `proxy_buffering off;`
            - Caddy: `flush_interval -1`
            - Apache: `flushpackets=on`

            SSE can only be enabled when `live` is also `true`.
        - name: experimental_live_sse
          in: query
          schema:
            type: boolean
          deprecated: true
          description: |-
            Deprecated in favor of `live_sse`. Use `live_sse` instead.
            This parameter will be removed in a future version.
        - name: cursor
          in: query
          schema:
            type: string
          description: |-
            This is a cursor generated by the server during live requests. It helps bust caches for
            responses from previous long-polls.
        - name: handle
          in: query
          schema:
            type: string
          example: '3833821-1721812114261'
          description: |-
            The shape handle returned by the initial shape request.

            This is a required parameter when this is not an initial sync request,
            i.e. when offset is not `-1`.
        - name: where
          in: query
          schema:
            type: string
          description: |-
            Optional where clause to filter rows in the `table`.

            This should be a valid PostgreSQL WHERE clause using SQL syntax.

            For more details on what is supported and what is optimal,
            see the [where clause documentation](https://electric-sql.com/docs/sync/guides/shapes#where-clause).

            If this where clause uses a positional parameter, it's value must be provided under `params[n]=`
            query parameter.
          examples:
            title_filter:
              value: |
                "title = 'Electric'"
              summary: Only include rows where the title is 'Electric'
            status_filter:
              value: |
                "status IN ('backlog', 'todo')"
              summary: Only include rows whose status is either 'backlog' or 'todo'
        - name: params
          in: query
          style: deepObject
          explode: true
          schema:
            type: object
            patternProperties:
              '^\d+$':
                type: string
          description: |-
            Optional params to replace inside the where clause. Uses an "exploded object" syntax (see examples).

            These values will be safely interpolated inside the where clause, so you don't need to worry about
            escaping user input when building a where clause.

            If where clause mentions a posisional parameter, it becomes required to provide it.
          examples:
            params:
              value:
                1: value1
              summary: replace placeholder `$1` inside the where clause with `value1`

        - name: columns
          in: query
          schema:
            type: string
          description: |-
            Optional list of columns to sync in the rows from the `table`.

            This is a projection setting for reducing the data sent to the client.
            If `queryable_columns` is set, `columns` may only include columns from
            that allow-list. If `queryable_columns` is set and `columns` is omitted,
            Electric syncs the queryable columns by default.

            They should always include the primary key columns, and should be formed
            as a comma separated list of column names exactly as they are in the database schema.

            If the identifier was defined as case sensitive and/or with special characters, then\
            you must quote it in the `columns` parameter as well.
          examples:
            select_columns:
              value: 'id,title,status'
              summary: Only include the id, title, and status columns.
            select_columns_special:
              value: 'id,"Status-Check"'
              summary: Only include id and Status-Check columns, quoting the identifiers where necessary.
        - name: queryable_columns
          in: query
          schema:
            type: string
          description: |-
            Optional list of columns that may be referenced by subset WHERE clauses,
            subset ORDER BY clauses, and the `columns` projection.

            This is an allow-list for what client-controlled subset requests may query
            or sync. It does not force every listed column to be synced, and it does
            not restrict the main shape WHERE clause.

            Queryable columns should always include the primary key columns, and should
            be formed as a comma separated list of column names exactly as they are in
            the database schema.
          examples:
            queryable_columns:
              value: 'id,title,org_id'
              summary: Allow filtering by org_id while syncing a narrower columns projection.
        - name: replica
          in: query
          schema:
            type: string
            enum:
              - default
              - full
          description: |-
            Modifies the data sent in update and delete change messages.

            When `replica=default` (the default) only changed columns are
            included in the `value` of an update message and only the primary
            keys are sent for a delete.

            When set to `full` the entire row will be sent for updates and
            deletes. `old_value` will also be present on update messages,
            containing the previous value for changed columns.

            Note that insert operations always include the full row,
            in either mode.
        - name: log
          in: query
          schema:
            type: string
            enum:
              - full
              - changes_only
            default: full
          examples:
            full_snapshot:
              value: 'full'
              summary: Load complete historical data (default)
            changes_only:
              value: 'changes_only'
              summary: Skip historical data, only receive real-time changes
          description: |-
            Controls the initial data loading mode for the shape.

            When `log=full` (the default), the server creates an initial snapshot
            of all data matching the shape definition and streams it to the client
            before delivering real-time updates.

            When `log=changes_only`, the server skips the initial snapshot creation.
            The client will only receive changes that occur after the shape is
            established, without seeing the base data. This is useful for:

            - Event streams where historical data isn't needed
            - Applications that fetch their initial state through `subset__*` parameters
            - Reducing initial sync time when combined with `offset=now`

            In `changes_only` mode, you can use the client's `requestSnapshot` method
            to fetch subsets of data on-demand while tracking which changes to skip.
        - name: subset__where
          in: query
          schema:
            type: string
          examples:
            status_filter:
              value: "status = 'active'"
              summary: Filter subset to only active records
            priority_filter:
              value: "priority = 'high' AND status = 'open'"
              summary: Filter to high priority open items
          description: |-
            Optional WHERE clause to filter a subset of the shape data.

            Presence of this or other `subset__*` parameters in the request makes the server
            return a subset snapshot instead of the regular shape sync.

            This allows you to fetch a specific portion of the shape's data with
            additional filtering beyond the main shape's WHERE clause. This filter is
            always applied in addition to the main shape's WHERE clause, so it's not possible
            to get data that doesn't match the main shape's WHERE clause.
        - name: subset__params
          in: query
          schema:
            type: string
            format: json
          description: |-
            Parameters for the subset WHERE clause as a JSON string.
            The JSON should be an object mapping positional parameter numbers to their values,
            for example: `{"1":"value1","2":"value2"}` to replace `$1` and `$2` in the subset WHERE clause.

            Presence of this or other `subset__*` parameters in the request makes the server
            return a subset snapshot instead of the regular shape sync.
          examples:
            single_param:
              value: '{"1":"high"}'
              summary: Replace $1 in subset WHERE clause with "high"
            multiple_params:
              value: '{"1":"active","2":"100"}'
              summary: Replace $1 with "active" and $2 with "100"
        - name: subset__limit
          in: query
          schema:
            type: integer
            minimum: 1
          examples:
            page_size:
              value: 50
              summary: Return maximum of 50 rows
            small_batch:
              value: 10
              summary: Small batch of 10 rows
          description: |-
            Maximum number of rows to return in the subset snapshot.

            Presence of this or other `subset__*` parameters in the request makes the server
            return a subset snapshot instead of the regular shape sync.

            When `limit` or `offset` is specified, `subset__order_by` becomes required.
        - name: subset__offset
          in: query
          schema:
            type: integer
            minimum: 0
          examples:
            first_page:
              value: 0
              summary: Start from the first row
            second_page:
              value: 50
              summary: Skip first 50 rows for pagination
          description: |-
            Number of rows to skip in the subset snapshot (for pagination).

            Presence of this or other `subset__*` parameters in the request makes the server
            return a subset snapshot instead of the regular shape sync.

            When `limit` or `offset` is specified, `subset__order_by` becomes required.
        - name: subset__order_by
          in: query
          schema:
            type: string
          examples:
            by_created:
              value: 'created_at DESC'
              summary: Order by creation date, newest first
            by_priority:
              value: 'priority ASC, created_at DESC NULLS LAST'
              summary: Order by priority ascending, then by date descending
          description: |-
            ORDER BY clause for the subset snapshot, determining the row ordering. Uses
            same syntax as `ORDER BY` clause in PostgreSQL.

            Presence of this or other `subset__*` parameters in the request makes the server
            return a subset snapshot instead of the regular shape sync.

            This becomes required when using `subset__limit` or `subset__offset`.

        - $ref: '#/components/parameters/secret'
        - $ref: '#/components/parameters/api_secret'
        # Headers
        - name: If-None-Match
          in: header
          schema:
            type: string
          # TODO: is this description below correct?
          description: Re-validate the shape if the etag doesn't match.
      responses:
        '200':
          description: The shape request was successful.
          headers:
            cache-control:
              schema:
                type: string
              example: 'public, max-age=60, stale-while-revalidate=300'
              description: |-
                Cache control header as a string of comma separated directives.

                Supported directives are: `max-age`, `stale-while-revalidate`.
            etag:
              schema:
                type: string
              example: '3833821-1721812114261:26800584_4:26800584_4'
              description: |-
                Etag header specifying the shape handle and offset for efficient caching.

                In the format `{shape_handle}:{start_offset}:{end_offset}`.
            electric-cursor:
              schema:
                type: string
              example: '1674440'
              description: |-
                If present, provides a cursor to use as the value of the `cursor`
                parameter in the next `live` mode long polling request.

                This works around some inconsistent request coalescing behaviour
                with different CDNs.
            electric-offset:
              schema:
                type: string
              example: '26800584_4'
              description: |-
                The latest offset in the batch of data you have received.

                If no data is returned, this will be equal to the `offset` parameter
                you have provided.

                Must be used as the value of the `offset` parameter in your
                next request.
            electric-handle:
              schema:
                type: string
              example: '3833821-1721812114261'
              description: |-
                The shape handle.

                Must be provided as the value of the `handle` parameter when making
                subsequent requests where `offset` is not `-1`.
            electric-schema:
              schema:
                type: string
                example: '{"id":{"type":"int4","dimensions":0},"title":{"type":"text","dimensions":0},"status":{"type":"text","dimensions":0,"max_length":8}}'
                description: |-
                  Only present on responses to non-live requests.
                  A JSON string of an object that maps column names to the corresponding schema object.
                  The schema object contains the type of the column, the number of dimensions, and possibly additional properties.
                  Non-array types have a dimension of `0`, while array types have a dimension of 1 or more.
                  For instance, an array of booleans would have a type of `bool` and a dimension of `1`.
                  Some types provide additional properties,
                  e.g.: `VARCHAR(8)` has an additional `“max_length": 8` property,
                        `BPCHAR(9)` has an additional `"length": 9` property,
                        `TIME(3)` has an additional `"precision": 3` property,
                        `NUMERIC(8,5)` has additional `"precision": 8` and `"scale": 5` properties,
                        `INTERVAL(4)` has an additional `"precision": 4` property,
                        `INTERVAL MINUTE TO SECOND` has an additional `"fields": "MINUTE TO SECOND"` property,
                        `BIT(5)` has an additional `"length": 5` property.
            electric-up-to-date:
              schema:
                description: |-
                  If present, this header indicates that the response ends with
                  an `up-to-date` control message, indicating that the client has
                  received all of the data that the server is aware of and can
                  safely process/apply any accumulated messages.
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    description: |-
                      Array of message objects returned for regular shape sync requests
                      (when no `subset__*` parameters are present).
                    items:
                      type: object
                      description: Message object
                      required:
                        - headers
                      properties:
                        headers:
                          type: object
                          description: |-
                            Metadata about the message.

                            Messages can be `control` messages, providing information or
                            instructions to the client. Or they can be operations that
                            performed a certain `operation` on a row of data in the shape.

                            Control messages include:
                            - `up-to-date`: Indicates the client has received all available data
                            - `must-refetch`: Indicates the client must discard local data and re-sync
                            - `snapshot-end`: Marks the end of a subset snapshot, includes PostgreSQL
                              snapshot metadata (xmin, xmax, xip_list) for tracking which changes to skip
                          properties:
                            control:
                              type: string
                              enum:
                                - up-to-date
                                - must-refetch
                                - snapshot-end
                            xmin:
                              type: string
                              description: |-
                                Minimum transaction ID in the snapshot (for `snapshot-end` control messages only).

                                Part of the PostgreSQL snapshot metadata that allows clients to determine
                                which changes have been incorporated into a snapshot.
                            xmax:
                              type: string
                              description: |-
                                Maximum transaction ID in the snapshot (for `snapshot-end` control messages only).

                                Part of the PostgreSQL snapshot metadata that allows clients to determine
                                which changes have been incorporated into a snapshot.
                            xip_list:
                              type: array
                              items:
                                type: string
                              description: |-
                                List of transaction IDs in progress during the snapshot (for `snapshot-end` control messages only).

                                Part of the PostgreSQL snapshot metadata that allows clients to determine
                                which changes have been incorporated into a snapshot.
                            operation:
                              type: string
                              enum:
                                - insert
                                - update
                                - delete
                              description: The type of operation performed on the row of the shape.
                            lsn:
                              type: string
                              description: |-
                                The logical sequence number of the operation.

                                Only present on operations that were received from the event stream.
                                It's missing on initial query results and on compacted items.
                                Operations with the same LSN were committed in the same transaction and
                                can be ordered by `op_position` within the same LSN.
                            op_position:
                              type: integer
                              description: |-
                                The position of the operation in the transaction.

                                Only present on operations that were received from the event stream.
                                It's missing on initial query results and on compacted items.
                            last:
                              type: boolean
                              description: |-
                                Whether this is the last operation in the transaction for this shape.

                                Last operation in a transaction for the shape does not mean a last
                                operation in the transaction for the database.

                                Only present on operations that were received from the event stream.
                                It's missing on initial query results and on compacted items.
                            txids:
                              type: array
                              description: |-
                                The list of transaction IDs that this operation was part of.

                                Currently, this will only contain a single transaction ID, but future
                                stream processors may merge operations from multiple transactions into a single
                                operation in the event stream.
                            snapshot_mark:
                              type: integer
                              description: |-
                                Random number identifying which snapshot this operation belongs to.

                                Only present on operation messages that are part of a subset snapshot response.
                                Used to match snapshot data with its corresponding `snapshot-end` control message.
                        key:
                          type: string
                          description: Row ID
                        value:
                          type: object
                          description: |-
                            The row data.

                            Note that this does not necessarily contain the whole row:

                            - for inserts it will contain the whole row
                            - for updates it will contain the primary key and the changed values
                            - for deletes it will contain just the primary key

                            The values are strings that are formatted according to Postgres' display settings.
                            Some Postgres types support several display settings, we format values consistently according to the following display settings:

                            - `bytea_output = 'hex'`
                            - `DateStyle = 'ISO, DMY'`
                            - `TimeZone = 'UTC'`
                            - `IntervalStyle = 'iso_8601'`
                            - `extra_float_digits = 1`
                        old_value:
                          type: object
                          description: |-
                            The previous value for changed columns on an update.

                            Only present on update messages when `replica=full`.
                  - type: object
                    description: |-
                      Object containing subset snapshot data and metadata, returned when
                      any `subset__*` parameters are present in the request.
                    required:
                      - data
                      - metadata
                    properties:
                      metadata:
                        type: object
                        description: |-
                          PostgreSQL snapshot metadata for tracking which changes to skip.
                          This response format is returned when any `subset__*` parameters are present in the request.
                        properties:
                          xmin:
                            type: string
                            description: Minimum transaction ID in the snapshot (uint64 as string).
                          xmax:
                            type: string
                            description: Maximum transaction ID in the snapshot (uint64 as string).
                          xip_list:
                            type: array
                            items:
                              type: string
                            description: List of transaction IDs that were in progress during the snapshot (uint64 as strings).
                          snapshot_mark:
                            type: integer
                            description: Random number identifying this snapshot, matching the value in operation headers.
                          database_lsn:
                            type: string
                            description: Database log sequence number at the time the snapshot was taken.
                      data:
                        type: array
                        description: Array of operation messages (no control messages) representing the subset snapshot data.
                        items:
                          type: object
                          description: Operation message
                          properties:
                            headers:
                              type: object
                              description: Metadata about the operation.
                              properties:
                                operation:
                                  type: string
                                  enum:
                                    - insert
                                    - update
                                    - delete
                                  description: The type of operation performed on the row of the shape.
                                snapshot_mark:
                                  type: integer
                                  description: |-
                                    Random number identifying this snapshot.
                                    Matches the `snapshot_mark` in the metadata object.
                                lsn:
                                  type: string
                                  description: |-
                                    The logical sequence number of the operation.

                                    Only present on operations that were received from the event stream.
                                    It's missing on initial query results and on compacted items.
                                op_position:
                                  type: integer
                                  description: |-
                                    The position of the operation in the transaction.

                                    Only present on operations that were received from the event stream.
                                txids:
                                  type: array
                                  description: |-
                                    The list of transaction IDs that this operation was part of.
                            key:
                              type: string
                              description: Row ID
                            value:
                              type: object
                              description: The row data.
                            old_value:
                              type: object
                              description: |-
                                The previous value for changed columns on an update.
                                Only present when `replica=full`.
              examples:
                default:
                  summary: Regular shape sync with insert operations
                  value:
          

# --- truncated at 32 KB (47 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/electric-sql/refs/heads/main/openapi/electric-sql-http-sync-api-openapi.yml