ElectricSQL Shape API

The Shape API from ElectricSQL — 1 operation(s) for shape.

OpenAPI Specification

electric-sql-shape-api-openapi.yml Raw ↑
openapi: 3.1.0
info:
  title: Electric HTTP Shape 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
tags:
- name: Shape
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:
      - 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'
      - name: If-None-Match
        in: header
        schema:
          type: string
        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.\nA JSON string of an object that maps column names to the corresponding schema object.\nThe schema object contains the type of the column, the number of dimensions, and possibly additional properties.\nNon-array types have a dimension of `0`, while array types have a dimension of 1 or more.\nFor instance, an array of booleans would have a type of `bool` and a dimension of `1`.\nSome types provide additional properties,\ne.g.: `VARCHAR(8)` has an additional `“max_length\": 8` property,\n      `BPCHAR(9)` has an additional `\"length\": 9` property,\n      `TIME(3)` has an additional `\"precision\": 3` property,\n      `NUMERIC(8,5)` has additional `\"precision\": 8` and `\"scale\": 5` properties,\n      `INTERVAL(4)` has an additional `\"precision\": 4` property,\n      `INTERVAL MINUTE TO SECOND` has an additional `\"fields\": \"MINUTE TO SECOND\"` property,\n      `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.\n\nMessages can be `control` messages, providing information or\ninstructions to the client. Or they can be operations that\nperformed a certain `operation` on a row of data in the shape.\n\nControl messages include:\n- `up-to-date`: Indicates the client has received all available data\n- `must-refetch`: Indicates the client must discard local data and re-sync\n- `snapshot-end`: Marks the end of a subset snapshot, includes PostgreSQL\n  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:
                  - headers:
                      operation: insert
                      lsn: 1234
                      op_position: 0
                    key: issue-1
                    value:
                      id: issue-1
                      title: Electric
                      status: backlog
                  - headers:
                      operation: insert
                      lsn: 1234
                      op_position: 7
                    key: issue-2
                    value:
                      id: issue-2
                      title: Hello
                      status: backlog
                  - headers:
                      control: up-to-date
                subset_snapshot:
                  summary: Subset snapshot with data and metadata
                  value:
                    data:
                    - headers:
                        operation: insert
                        snapshot_mark: 42
                        txids:
                        - '1020'
                      key: issue-3
                      value:
                        id: issue-3
                        title: High Priority
                        status: backlog
                    - headers:
                        operation: insert
                        snapshot_mark: 42
                        txids:
                        - '1020'
                      key: issue-5
                      value:
                        id: issue-5
                        title: Another High Priority
                        status: todo
                    metadata:
                      xmin: '1000'
                      xmax: '1050'
                      xip_list:
                      - '1025'
                      - '1030'
                      snapshot_mark: 42
                      database_lsn: 0/16B3F70
            text/event-stream:
              description: 'Server-Sent Events (SSE) format when `live_sse=true` is used.


                Each message is sent with the SSE `data:` prefix followed by a JSON payload.

                Keep-alive comments are sent as `: keep-alive` every 21 seconds.


                Note: SSE responses use `Content-Type: text/event-stream` but contain

                the same JSON message structures as the regular `application/json` responses.'
              examples:
                sse_stream:
                  summary: SSE stream with insert operations and control message
                  value: 'data: {"headers":{"operation":"insert","lsn":"1234","op_position":0},"key":"issue-1","value":{"id":"issue-1","title":"Electric","status":"backlog"}}


                    data: {"headers":{"operation":"insert","lsn":"1234","op_position":7},"key":"issue-2","value":{"id":"issue-2","title":"Hello","status":"backlog"}}


                    data: {"headers":{"control":"up-to-date","global_last_seen_lsn":"0/1234567"}}


                    : keep-alive

                    '
        '400':
          description: Bad request.
        '40

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