{ "openapi": "3.1.0", "info": { "title": "Stripe Sync Engine", "version": "1.0.0", "description": "Stripe Sync Engine — stateless, one-shot source/destination sync over HTTP.\nAll sync endpoints accept configuration via the `X-Pipeline` header (JSON-encoded PipelineConfig). Optional cursor state can be provided via `X-State`.\n\n## Endpoints\n\n| Method | Path | Summary |\n|--------|------|---------|\n| GET | /health | Health check |\n| POST | /pipeline_check | Check connector connection |\n| POST | /pipeline_setup | Set up destination schema |\n| POST | /pipeline_teardown | Tear down destination schema |\n| POST | /source_discover | Discover available streams |\n| POST | /pipeline_read | Read records from source |\n| POST | /pipeline_write | Write records to destination |\n| POST | /pipeline_sync | Run sync pipeline (read → write) |\n| GET | /meta/sources | List available source connectors |\n| GET | /meta/sources/{type} | Get source connector spec |\n| GET | /meta/destinations | List available destination connectors |\n| GET | /meta/destinations/{type} | Get destination connector spec |" }, "paths": { "/health": { "get": { "operationId": "health", "tags": [ "Status" ], "summary": "Health check", "responses": { "200": { "description": "Server is healthy", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean", "const": true }, "hostname": { "type": "string" }, "commit": { "type": "string" }, "commit_url": { "type": "string" }, "build_date": { "type": "string" } }, "required": [ "ok", "hostname" ], "additionalProperties": false } } } } } } }, "/pipeline_check": { "post": { "operationId": "pipeline_check", "tags": [ "Stateless Sync API" ], "summary": "Check connector connection", "description": "Validates the source/destination config and tests connectivity. Streams NDJSON messages (connection_status, log, trace) tagged with _emitted_by.", "parameters": [ { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } } ], "responses": { "200": { "description": "NDJSON stream of check messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/CheckOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/pipeline_setup": { "post": { "operationId": "pipeline_setup", "tags": [ "Stateless Sync API" ], "summary": "Set up destination schema", "description": "Creates destination tables and applies migrations. Streams NDJSON messages (control, log, trace) tagged with _emitted_by. Pass ?only=destination to run destination setup alone (e.g. optimistic table creation) or ?only=source to isolate the source.", "parameters": [ { "in": "query", "name": "only", "schema": { "description": "Run only the source or destination side. Useful for optimistic destination setup (e.g. creating tables early in a UI) or isolating a connector when debugging.", "example": "destination", "type": "string", "enum": [ "source", "destination" ] }, "description": "Run only the source or destination side. Useful for optimistic destination setup (e.g. creating tables early in a UI) or isolating a connector when debugging." }, { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } } ], "responses": { "200": { "description": "NDJSON stream of setup messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/SetupOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/pipeline_teardown": { "post": { "operationId": "pipeline_teardown", "tags": [ "Stateless Sync API" ], "summary": "Tear down destination schema", "description": "Drops destination tables. Streams NDJSON messages (log, trace) tagged with _emitted_by. Pass ?only=destination or ?only=source to run a single side.", "parameters": [ { "in": "query", "name": "only", "schema": { "description": "Run only the source or destination side. Useful for optimistic destination setup (e.g. creating tables early in a UI) or isolating a connector when debugging.", "example": "destination", "type": "string", "enum": [ "source", "destination" ] }, "description": "Run only the source or destination side. Useful for optimistic destination setup (e.g. creating tables early in a UI) or isolating a connector when debugging." }, { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } } ], "responses": { "200": { "description": "NDJSON stream of teardown messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/TeardownOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/source_discover": { "post": { "operationId": "source_discover", "tags": [ "Stateless Sync API" ], "summary": "Discover available streams", "description": "Streams NDJSON messages (catalog, logs, traces) for the configured source.", "parameters": [ { "in": "header", "name": "x-source", "required": true, "description": "JSON-encoded source config ({ type, ...config })", "content": { "application/json": { "schema": { "type": "object", "properties": { "type": { "type": "string" } }, "required": [ "type" ], "additionalProperties": {} } } } } ], "responses": { "200": { "description": "NDJSON stream of discover messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/DiscoverOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/pipeline_read": { "post": { "operationId": "pipeline_read", "tags": [ "Stateless Sync API" ], "summary": "Read records from source", "description": "Streams NDJSON messages (records, state, catalog). Optional NDJSON body provides live events as input.", "parameters": [ { "in": "query", "name": "state_limit", "schema": { "description": "Stop streaming after N state messages.", "example": "100", "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "description": "Stop streaming after N state messages." }, { "in": "query", "name": "time_limit", "schema": { "description": "Stop streaming after N seconds.", "example": "10", "type": "number", "exclusiveMinimum": 0 }, "description": "Stop streaming after N seconds." }, { "in": "query", "name": "run_id", "schema": { "description": "Optional sync run identifier used to track bounded sync progress.", "example": "run_demo", "type": "string" }, "description": "Optional sync run identifier used to track bounded sync progress." }, { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } }, { "in": "header", "name": "x-state", "required": false, "description": "JSON-encoded SyncState ({ source, destination, sync_run }). Falls back to empty state if invalid.", "content": { "application/json": { "schema": { "default": { "source": { "streams": {}, "global": {} }, "destination": {}, "sync_run": { "progress": { "started_at": "1970-01-01T00:00:00.000Z", "elapsed_ms": 0, "global_state_count": 0, "derived": { "status": "started", "records_per_second": 0, "states_per_second": 0 }, "streams": {} } } }, "$ref": "#/components/schemas/SyncState" } } } } ], "requestBody": { "required": false, "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/SourceInputMessage" } } } }, "responses": { "200": { "description": "NDJSON stream of sync messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/Message" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/pipeline_write": { "post": { "operationId": "pipeline_write", "tags": [ "Stateless Sync API" ], "summary": "Write records to destination", "description": "Reads NDJSON messages from the request body and writes them to the destination. Pipe /read output as input.", "parameters": [ { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } } ], "requestBody": { "required": true, "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/Message" } } } }, "responses": { "200": { "description": "NDJSON stream of write result messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/DestinationOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/pipeline_sync": { "post": { "operationId": "pipeline_sync", "tags": [ "Stateless Sync API" ], "summary": "Run sync pipeline (read → write)", "description": "Without a request body, reads from the source connector and writes to the destination (backfill mode). With an NDJSON request body, uses the provided messages as input instead of reading from the source (push mode — e.g. piped webhook events).", "parameters": [ { "in": "query", "name": "state_limit", "schema": { "description": "Stop streaming after N state messages.", "example": "100", "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 }, "description": "Stop streaming after N state messages." }, { "in": "query", "name": "time_limit", "schema": { "description": "Stop streaming after N seconds.", "example": "10", "type": "number", "exclusiveMinimum": 0 }, "description": "Stop streaming after N seconds." }, { "in": "query", "name": "run_id", "schema": { "description": "Optional sync run identifier used to track bounded sync progress.", "example": "run_demo", "type": "string" }, "description": "Optional sync run identifier used to track bounded sync progress." }, { "in": "header", "name": "x-pipeline", "required": true, "description": "JSON-encoded PipelineConfig", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PipelineConfig" } } } }, { "in": "header", "name": "x-state", "required": false, "description": "JSON-encoded SyncState ({ source, destination, sync_run }). Falls back to empty state if invalid.", "content": { "application/json": { "schema": { "default": { "source": { "streams": {}, "global": {} }, "destination": {}, "sync_run": { "progress": { "started_at": "1970-01-01T00:00:00.000Z", "elapsed_ms": 0, "global_state_count": 0, "derived": { "status": "started", "records_per_second": 0, "states_per_second": 0 }, "streams": {} } } }, "$ref": "#/components/schemas/SyncState" } } } } ], "requestBody": { "required": false, "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/SourceInputMessage" } } } }, "responses": { "200": { "description": "NDJSON stream of sync messages", "content": { "application/x-ndjson": { "schema": { "$ref": "#/components/schemas/SyncOutput" } } } }, "400": { "description": "Invalid params", "content": { "application/json": { "schema": { "type": "object", "properties": { "error": {} }, "required": [ "error" ], "additionalProperties": false } } } } } } }, "/meta/sources": { "get": { "operationId": "meta_sources_list", "tags": [ "Meta" ], "summary": "List available source connectors", "responses": { "200": { "description": "Available source connectors with their JSON Schema configs", "content": { "application/json": { "schema": { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "config_schema": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "type": { "type": "string" } }, "required": [ "config_schema", "type" ], "additionalProperties": false } } }, "required": [ "items" ], "additionalProperties": false } } } } } } }, "/meta/sources/{type}": { "get": { "operationId": "meta_sources_get", "tags": [ "Meta" ], "summary": "Get source connector spec", "parameters": [ { "in": "path", "name": "type", "schema": { "type": "string" }, "required": true } ], "responses": { "200": { "description": "Source connector spec", "content": { "application/json": { "schema": { "type": "object", "properties": { "config_schema": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "config_schema" ], "additionalProperties": false } } } }, "404": { "description": "Source connector not found" } } } }, "/meta/destinations": { "get": { "operationId": "meta_destinations_list", "tags": [ "Meta" ], "summary": "List available destination connectors", "responses": { "200": { "description": "Available destination connectors with their JSON Schema configs", "content": { "application/json": { "schema": { "type": "object", "properties": { "items": { "type": "array", "items": { "type": "object", "properties": { "config_schema": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "type": { "type": "string" } }, "required": [ "config_schema", "type" ], "additionalProperties": false } } }, "required": [ "items" ], "additionalProperties": false } } } } } } }, "/meta/destinations/{type}": { "get": { "operationId": "meta_destinations_get", "tags": [ "Meta" ], "summary": "Get destination connector spec", "parameters": [ { "in": "path", "name": "type", "schema": { "type": "string" }, "required": true } ], "responses": { "200": { "description": "Destination connector spec", "content": { "application/json": { "schema": { "type": "object", "properties": { "config_schema": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "config_schema" ], "additionalProperties": false } } } }, "404": { "description": "Destination connector not found" } } } } }, "components": { "schemas": { "RecordMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "record" }, "record": { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream (table) name this record belongs to." }, "data": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "The record payload as a key-value map." }, "emitted_at": { "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$", "description": "ISO 8601 timestamp when the record was emitted by the source." } }, "required": [ "stream", "data", "emitted_at" ], "description": "One record for one stream." } }, "required": [ "type", "record" ] }, "SourceStateMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "source_state" }, "source_state": { "anyOf": [ { "type": "object", "properties": { "state_type": { "default": "stream", "type": "string", "const": "stream" }, "stream": { "type": "string", "description": "Stream being checkpointed." }, "data": { "description": "Opaque checkpoint data — only the source understands its contents. The orchestrator persists it keyed by stream and passes it back on resume." } }, "required": [ "stream", "data" ], "description": "Per-stream checkpoint for resumable syncs." }, { "type": "object", "properties": { "state_type": { "type": "string", "const": "global" }, "data": { "description": "Sync-wide state shared across all streams (e.g. a global events cursor)." } }, "required": [ "state_type", "data" ], "description": "Sync-wide checkpoint shared across all streams." } ] } }, "required": [ "type", "source_state" ] }, "CatalogMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "catalog" }, "catalog": { "type": "object", "properties": { "streams": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "Collection name (e.g. \"customers\", \"invoices\", \"pg_public.users\")." }, "primary_key": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "description": "Paths to fields that uniquely identify a record within this stream. Supports composite keys and nested paths. e.g. [[\"id\"]] or [[\"account_id\"], [\"created\"]]" }, "json_schema": { "description": "JSON Schema describing the record shape. Discovered at runtime or provided by config.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "metadata": { "description": "Source-specific metadata that applies to every record in this stream. The destination can use these for schema naming, partitioning, etc. Examples: Stripe: { api_version, account_id, live_mode }.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "newer_than_field": { "description": "Field whose value increases monotonically. Destination uses it to skip stale writes (e.g. \"updated\").", "type": "string" }, "soft_delete_field": { "description": "Field in record data that signals a soft delete (e.g. \"deleted\"). Destination uses this to classify upserts as deletes when the field is truthy.", "type": "string" } }, "required": [ "name", "primary_key" ], "description": "A named collection of records — analogous to a table or API resource." }, "description": "All streams available from this source." } }, "required": [ "streams" ], "description": "Catalog of available streams." } }, "required": [ "type", "catalog" ] }, "LogMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "log" }, "log": { "type": "object", "properties": { "level": { "type": "string", "enum": [ "debug", "info", "warn", "error" ], "description": "Log severity level." }, "message": { "type": "string", "description": "Human-readable log message." }, "data": { "description": "Structured log fields emitted alongside the message.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "level", "message" ], "description": "Structured log output from a connector." } }, "required": [ "type", "log" ] }, "SpecMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "spec" }, "spec": { "type": "object", "properties": { "config": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "JSON Schema for the connector's configuration object." }, "source_state_stream": { "description": "JSON Schema for per-stream state (cursor/checkpoint shape). See also SourceState.global for sync-wide cursors.", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "source_input": { "description": "JSON Schema for the read() input parameter (e.g. a webhook event).", "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "config" ], "description": "JSON Schema describing the configuration a connector requires." } }, "required": [ "type", "spec" ] }, "ConnectionStatusMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "connection_status" }, "connection_status": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "succeeded", "failed" ], "description": "Whether the connection check passed." }, "message": { "description": "Human-readable explanation of the check result.", "type": "string" } }, "required": [ "status" ], "description": "Result of a connection check." } }, "required": [ "type", "connection_status" ] }, "StreamStatusMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "stream_status" }, "stream_status": { "oneOf": [ { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream being reported on." }, "status": { "type": "string", "const": "start" }, "time_range": { "description": "Full backfill time span for this stream.", "type": "object", "properties": { "gte": { "description": "Inclusive lower bound (ISO 8601).", "type": "string" }, "lt": { "description": "Exclusive upper bound (ISO 8601).", "type": "string" } } } }, "required": [ "stream", "status" ] }, { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream being reported on." }, "status": { "type": "string", "const": "range_complete" }, "range_complete": { "type": "object", "properties": { "gte": { "type": "string", "description": "Inclusive lower bound (ISO 8601)." }, "lt": { "type": "string", "description": "Exclusive upper bound (ISO 8601)." } }, "required": [ "gte", "lt" ], "description": "The sub-range that finished." } }, "required": [ "stream", "status", "range_complete" ] }, { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream being reported on." }, "status": { "type": "string", "const": "complete" } }, "required": [ "stream", "status" ] }, { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream being reported on." }, "status": { "type": "string", "const": "error" }, "error": { "type": "string", "description": "Human-readable error description." } }, "required": [ "stream", "status", "error" ] }, { "type": "object", "properties": { "stream": { "type": "string", "description": "Stream being reported on." }, "status": { "type": "string", "const": "skip" }, "reason": { "type": "string", "description": "Why the stream was skipped." } }, "required": [ "stream", "status", "reason" ] } ], "description": "Stream lifecycle event. Sources emit these; the engine tracks stream progress from them.", "type": "object", "discriminator": { "propertyName": "status" } } }, "required": [ "type", "stream_status" ] }, "ControlMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "control" }, "control": { "oneOf": [ { "type": "object", "properties": { "control_type": { "type": "string", "const": "source_config" }, "source_config": { "$ref": "#/components/schemas/SourceStripeConfig" } }, "required": [ "control_type", "source_config" ] }, { "type": "object", "properties": { "control_type": { "type": "string", "const": "destination_config" }, "destination_config": { "oneOf": [ { "$ref": "#/components/schemas/DestinationPostgresConfig" }, { "$ref": "#/components/schemas/DestinationGoogleSheetsConfig" } ] } }, "required": [ "control_type", "destination_config" ] } ], "description": "Control signal from a connector to the orchestrator.", "type": "object", "discriminator": { "propertyName": "control_type" } } }, "required": [ "type", "control" ] }, "ProgressMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "progress" }, "progress": { "$ref": "#/components/schemas/ProgressPayload" } }, "required": [ "type", "progress" ] }, "ProgressPayload": { "type": "object", "properties": { "started_at": { "type": "string", "description": "When this sync started (ISO 8601); generally equals time_ceiling." }, "elapsed_ms": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Wall-clock milliseconds since the sync run started." }, "global_state_count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Total source_state messages observed so far." }, "connection_status": { "description": "Set when source or destination emits connection_status: failed.", "type": "object", "properties": { "status": { "type": "string", "enum": [ "succeeded", "failed" ], "description": "Whether the connection check passed." }, "message": { "description": "Human-readable explanation of the check result.", "type": "string" } }, "required": [ "status" ] }, "derived": { "type": "object", "properties": { "status": { "$ref": "#/components/schemas/RunStatus" }, "records_per_second": { "type": "number", "description": "Overall throughput for the entire run." }, "states_per_second": { "type": "number", "description": "State checkpoints per second." } }, "required": [ "status", "records_per_second", "states_per_second" ], "description": "Computed aggregates." }, "streams": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": { "$ref": "#/components/schemas/StreamProgress" }, "description": "Per-stream progress, keyed by stream name." } }, "required": [ "started_at", "elapsed_ms", "global_state_count", "derived", "streams" ], "description": "Periodic sync progress emitted by the engine as a top-level message. Each emission is a full replacement." }, "RunStatus": { "type": "string", "enum": [ "started", "succeeded", "failed" ], "description": "succeeded = all streams completed/skipped; failed = connection_status failed OR any stream errored." }, "StreamProgress": { "type": "object", "properties": { "status": { "type": "string", "enum": [ "not_started", "started", "completed", "skipped", "errored" ], "description": "Current state, derived from stream_status events." }, "state_count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Number of state checkpoints for this stream." }, "record_count": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Records synced for this stream in this run." }, "message": { "description": "Human-readable status message (error reason, skip reason, etc).", "type": "string" }, "total_range": { "description": "Full backfill time span for this stream.", "type": "object", "properties": { "gte": { "type": "string", "description": "Inclusive lower bound (ISO 8601)." }, "lt": { "type": "string", "description": "Exclusive upper bound (ISO 8601)." } }, "required": [ "gte", "lt" ] }, "completed_ranges": { "description": "Completed time sub-ranges within the total_range.", "type": "array", "items": { "type": "object", "properties": { "gte": { "type": "string", "description": "Inclusive lower bound (ISO 8601)." }, "lt": { "type": "string", "description": "Exclusive upper bound (ISO 8601)." } }, "required": [ "gte", "lt" ] } } }, "required": [ "status", "state_count", "record_count" ], "description": "Per-stream progress snapshot." }, "EofMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "eof" }, "eof": { "$ref": "#/components/schemas/EofPayload" } }, "required": [ "type", "eof" ] }, "EofPayload": { "type": "object", "properties": { "status": { "description": "Terminal run status derived from stream outcomes.", "$ref": "#/components/schemas/RunStatus" }, "has_more": { "type": "boolean", "description": "Whether the client should continue with another request. true when cut off by limits; false when the source iterator exhausted naturally." }, "ending_state": { "description": "Full sync state at the end of this request. Round-trip this as starting_state on the next request.", "$ref": "#/components/schemas/SyncState" }, "run_progress": { "description": "Accumulated progress across all requests in this sync run.", "$ref": "#/components/schemas/ProgressPayload" }, "request_progress": { "description": "Progress for this specific request only.", "$ref": "#/components/schemas/ProgressPayload" } }, "required": [ "status", "has_more", "run_progress", "request_progress" ], "description": "Terminal message signaling end of this request." }, "SyncState": { "type": "object", "properties": { "source": { "$ref": "#/components/schemas/SourceState" }, "destination": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Destination connector state." }, "sync_run": { "type": "object", "properties": { "run_id": { "description": "Identifies a finite backfill run. Omit for continuous sync.", "type": "string" }, "time_ceiling": { "description": "Frozen upper bound (ISO 8601). Set on first invocation when run_id is present; reused on continuation.", "type": "string" }, "progress": { "description": "Accumulated progress from prior requests in this run.", "$ref": "#/components/schemas/ProgressPayload" } }, "required": [ "progress" ], "description": "Engine-managed run state — run_id, time_ceiling, accumulated progress." } }, "required": [ "source", "destination", "sync_run" ], "description": "Full sync checkpoint with separate sections for source, destination, and sync run. Connectors only see their own section; the engine manages routing." }, "SourceState": { "type": "object", "properties": { "streams": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Per-stream checkpoint data, keyed by stream name." }, "global": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {}, "description": "Source-wide state shared across all streams." } }, "required": [ "streams", "global" ], "description": "Source connector state — cursors, backfill progress, events cursors." }, "SourceInputMessage": { "type": "object", "properties": { "_emitted_by": { "description": "Who emitted this message: \"source/{type}\", \"destination/{type}\", or \"engine\". Set by the engine.", "type": "string" }, "_ts": { "description": "ISO 8601 timestamp when the engine observed this message.", "type": "string", "format": "date-time", "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$" }, "type": { "type": "string", "const": "source_input" }, "source_input": {} }, "required": [ "type", "source_input" ] }, "SourceStripeInput": { "type": "object", "properties": { "id": { "type": "string", "description": "Unique identifier for the object." }, "object": { "type": "string", "const": "event" }, "account": { "type": "string", "description": "The connected account that originates the event." }, "api_version": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "created": { "type": "number", "description": "Time at which the object was created. Measured in seconds since the Unix epoch." }, "data": { "type": "object", "properties": { "object": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} }, "previous_attributes": { "type": "object", "propertyNames": { "type": "string" }, "additionalProperties": {} } }, "required": [ "object" ], "additionalProperties": false }, "livemode": { "type": "boolean", "description": "Has the value `true` if the object exists in live mode or the value `false` if the object exists in test mode." }, "pending_webhooks": { "type": "number", "description": "Number of webhooks that haven't been successfully delivered (for example, to return a 20x response) to the URLs you specify." }, "request": { "anyOf": [ { "type": "object", "properties": { "id": { "anyOf": [ { "type": "string" }, { "type": "null" } ] }, "idempotency_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ] } }, "required": [ "id", "idempotency_key" ], "additionalProperties": false }, { "type": "null" } ] }, "type": { "type": "string", "description": "Description of the event (for example, `invoice.created` or `charge.refunded`)." } }, "required": [ "id", "object", "api_version", "created", "data", "livemode", "pending_webhooks", "request", "type" ], "additionalProperties": false }, "SourceConfig": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "stripe" }, "stripe": { "$ref": "#/components/schemas/SourceStripeConfig" } }, "required": [ "type", "stripe" ] } ], "type": "object", "discriminator": { "propertyName": "type" } }, "SourceStripeConfig": { "type": "object", "properties": { "api_key": { "type": "string", "description": "Stripe API key (sk_test_... or sk_live_...)" }, "account_id": { "type": "string", "description": "Stripe account ID (resolved from API if omitted)" }, "account_created": { "type": "integer", "minimum": 0, "maximum": 9007199254740991, "description": "Stripe account creation timestamp in unix seconds (resolved from API if omitted)" }, "livemode": { "type": "boolean", "description": "Whether this is a live mode sync" }, "api_version": { "type": "string", "enum": [ "2026-03-25.dahlia", "2026-02-25.clover", "2026-01-28.clover", "2025-12-15.clover", "2025-11-17.clover", "2025-10-29.clover", "2025-09-30.clover", "2025-08-27.basil", "2025-07-30.basil", "2025-06-30.basil", "2025-05-28.basil", "2025-04-30.basil", "2025-03-31.basil", "2025-02-24.acacia", "2025-01-27.acacia", "2024-12-18.acacia", "2024-11-20.acacia", "2024-10-28.acacia", "2024-09-30.acacia", "2024-06-20", "2024-04-10", "2024-04-03", "2023-10-16", "2023-08-16", "2022-11-15", "2022-08-01", "2020-08-27", "2020-03-02", "2019-12-03", "2019-11-05", "2019-10-17", "2019-10-08", "2019-09-09", "2019-08-14", "2019-05-16", "2019-03-14", "2019-02-19", "2019-02-11", "2018-11-08", "2018-10-31", "2018-09-24", "2018-09-06", "2018-08-23", "2018-07-27", "2018-05-21", "2018-02-28", "2018-02-06", "2018-02-05", "2018-01-23", "2017-12-14", "2017-08-15" ] }, "base_url": { "type": "string", "format": "uri", "description": "Override the Stripe API base URL (e.g. http://localhost:12111 for stripe-mock)" }, "webhook_url": { "type": "string", "format": "uri", "description": "URL for managed webhook endpoint registration" }, "webhook_secret": { "type": "string", "description": "Webhook signing secret (whsec_...) for signature verification" }, "websocket": { "type": "boolean", "description": "Enable WebSocket streaming for live events" }, "poll_events": { "type": "boolean", "description": "Enable events API polling for incremental sync after backfill" }, "webhook_port": { "type": "integer", "minimum": -9007199254740991, "maximum": 9007199254740991, "description": "Port for built-in webhook HTTP listener (e.g. 4242)" }, "revalidate_objects": { "type": "array", "items": { "type": "string" }, "description": "Object types to re-fetch from Stripe API on webhook (e.g. [\"subscription\"])" }, "backfill_limit": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "Max objects to backfill per stream (useful for testing)" }, "rate_limit": { "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991, "description": "Override max requests per second (default: auto-derived from API key mode — 20 live, 10 test)." } }, "required": [ "api_key" ], "additionalProperties": false }, "DestinationConfig": { "oneOf": [ { "type": "object", "properties": { "type": { "type": "string", "const": "postgres" }, "postgres": { "$ref": "#/components/schemas/DestinationPostgresConfig" } }, "required": [ "type", "postgres" ] }, { "type": "object", "properties": { "type": { "type": "string", "const": "google_sheets" }, "google_sheets": { "$ref": "#/components/schemas/DestinationGoogleSheetsConfig" } }, "required": [ "type", "google_sheets" ] } ], "type": "object", "discriminator": { "propertyName": "type" } }, "DestinationPostgresConfig": { "type": "object", "properties": { "url": { "type": "string", "description": "Postgres connection string" }, "connection_string": { "type": "string", "description": "Deprecated alias for url; prefer url" }, "schema": { "default": "public", "type": "string", "description": "Target schema name (e.g. \"stripe\")" }, "batch_size": { "default": 100, "type": "number", "description": "Records to buffer before flushing" }, "aws": { "type": "object", "properties": { "host": { "type": "string", "description": "Postgres host for RDS IAM auth" }, "port": { "default": 5432, "type": "number", "description": "Postgres port for RDS IAM auth" }, "database": { "type": "string", "description": "Database name for RDS IAM auth" }, "user": { "type": "string", "description": "Database user for RDS IAM auth" }, "region": { "type": "string", "description": "AWS region for RDS instance" }, "role_arn": { "type": "string", "description": "IAM role ARN to assume (cross-account)" }, "external_id": { "type": "string", "description": "External ID for STS AssumeRole" } }, "required": [ "host", "database", "user", "region" ], "additionalProperties": false, "description": "AWS RDS IAM authentication config" }, "ssl_ca_pem": { "type": "string", "description": "PEM-encoded CA certificate for SSL verification (required for verify-ca / verify-full with a private CA)" } }, "additionalProperties": false }, "DestinationGoogleSheetsConfig": { "type": "object", "properties": { "client_id": { "type": "string", "description": "Google OAuth2 client ID (env: GOOGLE_CLIENT_ID)" }, "client_secret": { "type": "string", "description": "Google OAuth2 client secret (env: GOOGLE_CLIENT_SECRET)" }, "access_token": { "type": "string", "description": "OAuth2 access token" }, "refresh_token": { "type": "string", "description": "OAuth2 refresh token" }, "spreadsheet_id": { "type": "string", "description": "Target spreadsheet ID (created if omitted)" }, "spreadsheet_title": { "default": "Stripe Sync", "type": "string", "description": "Title when creating a new spreadsheet" }, "batch_size": { "default": 50, "type": "number", "description": "Rows per Sheets API append call" } }, "required": [ "access_token", "refresh_token" ], "additionalProperties": false }, "Message": { "oneOf": [ { "$ref": "#/components/schemas/RecordMessage" }, { "$ref": "#/components/schemas/SourceStateMessage" }, { "$ref": "#/components/schemas/CatalogMessage" }, { "$ref": "#/components/schemas/LogMessage" }, { "$ref": "#/components/schemas/SpecMessage" }, { "$ref": "#/components/schemas/ConnectionStatusMessage" }, { "$ref": "#/components/schemas/StreamStatusMessage" }, { "$ref": "#/components/schemas/ControlMessage" }, { "$ref": "#/components/schemas/ProgressMessage" }, { "$ref": "#/components/schemas/EofMessage" }, { "$ref": "#/components/schemas/SourceInputMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "record": "#/components/schemas/RecordMessage", "source_state": "#/components/schemas/SourceStateMessage", "catalog": "#/components/schemas/CatalogMessage", "log": "#/components/schemas/LogMessage", "spec": "#/components/schemas/SpecMessage", "connection_status": "#/components/schemas/ConnectionStatusMessage", "stream_status": "#/components/schemas/StreamStatusMessage", "control": "#/components/schemas/ControlMessage", "progress": "#/components/schemas/ProgressMessage", "eof": "#/components/schemas/EofMessage", "source_input": "#/components/schemas/SourceInputMessage" } } }, "DiscoverOutput": { "oneOf": [ { "$ref": "#/components/schemas/CatalogMessage" }, { "$ref": "#/components/schemas/LogMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "catalog": "#/components/schemas/CatalogMessage", "log": "#/components/schemas/LogMessage" } } }, "DestinationOutput": { "$ref": "#/components/schemas/Message" }, "SyncOutput": { "oneOf": [ { "$ref": "#/components/schemas/SourceStateMessage" }, { "$ref": "#/components/schemas/StreamStatusMessage" }, { "$ref": "#/components/schemas/ProgressMessage" }, { "$ref": "#/components/schemas/ConnectionStatusMessage" }, { "$ref": "#/components/schemas/LogMessage" }, { "$ref": "#/components/schemas/EofMessage" }, { "$ref": "#/components/schemas/ControlMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "source_state": "#/components/schemas/SourceStateMessage", "stream_status": "#/components/schemas/StreamStatusMessage", "progress": "#/components/schemas/ProgressMessage", "connection_status": "#/components/schemas/ConnectionStatusMessage", "log": "#/components/schemas/LogMessage", "eof": "#/components/schemas/EofMessage", "control": "#/components/schemas/ControlMessage" } } }, "CheckOutput": { "oneOf": [ { "$ref": "#/components/schemas/ConnectionStatusMessage" }, { "$ref": "#/components/schemas/LogMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "connection_status": "#/components/schemas/ConnectionStatusMessage", "log": "#/components/schemas/LogMessage" } } }, "SetupOutput": { "oneOf": [ { "$ref": "#/components/schemas/ControlMessage" }, { "$ref": "#/components/schemas/LogMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "control": "#/components/schemas/ControlMessage", "log": "#/components/schemas/LogMessage" } } }, "TeardownOutput": { "oneOf": [ { "$ref": "#/components/schemas/LogMessage" } ], "type": "object", "discriminator": { "propertyName": "type", "mapping": { "log": "#/components/schemas/LogMessage" } } }, "TypedSourceInputMessage": { "type": "object", "properties": { "type": { "type": "string", "const": "source_input" }, "source_input": { "$ref": "#/components/schemas/SourceStripeInput" } }, "required": [ "type", "source_input" ], "additionalProperties": false }, "PipelineConfig": { "type": "object", "properties": { "source": { "$ref": "#/components/schemas/SourceConfig" }, "destination": { "$ref": "#/components/schemas/DestinationConfig" }, "streams": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string", "description": "Stream (table) name to sync." }, "sync_mode": { "description": "How the source reads this stream. Defaults to full_refresh.", "type": "string", "enum": [ "incremental", "full_refresh" ] }, "fields": { "description": "If set, only these fields are synced.", "type": "array", "items": { "type": "string" } }, "backfill_limit": { "description": "Cap backfill to this many records, then mark the stream complete.", "type": "integer", "exclusiveMinimum": 0, "maximum": 9007199254740991 } }, "required": [ "name" ], "additionalProperties": false } } }, "required": [ "source", "destination" ], "additionalProperties": false } } } }