> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kaireonai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connectors

> Manage external data source connections — 80 connector types are registered

<Frame caption="The Connectors page in the Data module.">
  <img src="https://mintcdn.com/kaireonai/l-jsUQlUEuA3B6hG/images/screenshots/connectors-list.png?fit=max&auto=format&n=l-jsUQlUEuA3B6hG&q=85&s=a10bdae77d494c6f4b0489732b8f4b51" alt="Connectors list view in the Data module" width="1440" height="900" data-path="images/screenshots/connectors-list.png" />
</Frame>

<Info>
  **Connector status:** 80 connector types are registered, but only four
  — `aws_s3`, `gcs`, `azure_blob`, `sftp` — can move data in a pipeline or a
  campaign delivery. The New Connector picker shows every other type as
  **Coming soon** and does not allow it to be created.
  Two — `amazon_kinesis` and `braze` — ship as **coming-soon**: they
  expose create/edit forms (and a working **Test Connection** probe for
  Amazon Kinesis), but pipeline runs that source from them no-op (the
  executor logs a message and returns zero rows). The 26 W16 expansion
  entries documented on [Connectors Expanded](/data/connectors/connectors-expanded)
  are also coming-soon. Every other registered type is production-ready.
</Info>

## GET /api/v1/connectors

List all connectors for the current tenant. Supports cursor-based pagination.

### Query Parameters

| Parameter | Type    | Default | Description                                                |
| --------- | ------- | ------- | ---------------------------------------------------------- |
| `limit`   | integer | `50`    | Max results per page (max 100)                             |
| `cursor`  | string  | —       | Cursor for pagination (ID of last item from previous page) |

### Response

```json theme={null}
{
  "data": [
    {
      "id": "conn_001",
      "name": "Production Snowflake",
      "type": "snowflake",
      "description": "Main data warehouse",
      "config": { "account": "xy12345.us-east-1", "warehouse": "COMPUTE_WH", "database": "ANALYTICS" },
      "authMethod": "access_key",
      "status": "active",
      "lastTestedAt": "2026-03-15T10:30:00.000Z",
      "lastError": null,
      "createdAt": "2026-01-10T08:00:00.000Z",
      "updatedAt": "2026-03-15T10:30:00.000Z"
    }
  ],
  "pagination": {
    "total": 12,
    "hasMore": false,
    "limit": 50,
    "cursor": null
  }
}
```

<Note>The `authConfig` field is never returned in list or detail responses to prevent secret leakage. The list endpoint also omits `lastSyncRowCount` and `lastSyncAt` (its `select` returns only `id`, `name`, `type`, `description`, `config`, `authMethod`, `status`, `lastTestedAt`, `lastError`, `createdAt`, `updatedAt`); those two sync fields are returned by the test-connection response and the pipeline-run flow.</Note>

***

## POST /api/v1/connectors

Create a new connector.

### Request Body

| Field         | Type   | Required | Description                                                                                          |
| ------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- |
| `name`        | string | Yes      | Unique connector name                                                                                |
| `type`        | string | Yes      | Connector type (see supported types below)                                                           |
| `description` | string | No       | Human-readable description                                                                           |
| `config`      | object | No       | Type-specific configuration (host, port, bucket, etc.). Also accepts `connectionConfig` as an alias. |
| `authMethod`  | string | No       | Authentication method. Default: `"access_key"`                                                       |
| `authConfig`  | object | No       | Credentials (encrypted at rest, never returned in responses)                                         |

<Info>
  The `config` field contains type-specific settings like `bucket`, `region`, `prefix` for S3 or `account`, `warehouse`, `database` for Snowflake. You can also send `connectionConfig` as an alias — the API accepts both names and merges them.
</Info>

### Supported Connector Types

| Type                                        | Status                              | Required Config Fields                                                   |
| ------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------ |
| `postgresql`, `mysql`, `redshift`           | Ready                               | `host`, `port`, `database`                                               |
| `snowflake`                                 | Ready                               | `account`, `warehouse`, `database`, `sourceTable`, `rowLimit` (optional) |
| `bigquery`                                  | Ready                               | `project`, `dataset`, `sourceTable`, `rowLimit` (optional)               |
| `mongodb`                                   | Ready                               | `host` or `connectionString`                                             |
| `kafka`, `confluent_kafka`                  | Ready (batch polling)               | `bootstrapServers`                                                       |
| `aws_s3`                                    | Ready                               | `bucket`, `region`                                                       |
| `gcs`                                       | Ready                               | `bucket`, `project`                                                      |
| `azure_blob`                                | Ready                               | `container`, `storageAccount`                                            |
| `sftp`                                      | Ready                               | `host`, `port`                                                           |
| `rest_api`, `webhook`                       | Ready                               | `url`                                                                    |
| `salesforce`, `hubspot`                     | Ready                               | `instanceUrl` or `apiKey`                                                |
| `databricks`                                | Ready                               | `host`, `httpPath`                                                       |
| `segment`, `shopify`, `stripe`, `mailchimp` | Ready                               | See `/data/overview` for fields                                          |
| `amazon_kinesis`                            | Coming soon (connection test works) | `streamName`, `region`                                                   |
| `braze`                                     | Coming soon                         | See `/data/overview` for fields                                          |

<Note>
  **Kafka is batch polling, not true streaming.** Each pipeline run opens a
  consumer, reads up to `maxMessages` records (default 1000) with a configurable
  wait timeout (default 15 seconds), commits offsets, and closes. True
  long-lived streaming requires a persistent worker that is not yet implemented.
</Note>

<Note>
  **Snowflake and BigQuery row limits.** Both connectors accept a `sourceTable`
  (required) and `rowLimit` (optional). The executor issues `SELECT * FROM <sourceTable> LIMIT <rowLimit>`.
  The default `rowLimit` is **100,000 rows** (demo-safe). Set to **0** to remove
  the cap — only do this once you have sized the target database and pipeline
  run budget to handle full-table reads.
</Note>

### Example

```bash theme={null}
curl -X POST https://playground.kaireonai.com/api/v1/connectors \
  -H "Content-Type: application/json" \
  -H "X-Tenant-Id: my-tenant" \
  -d '{
    "name": "Customer Data Warehouse",
    "type": "snowflake",
    "config": {
      "account": "xy12345.us-east-1",
      "warehouse": "COMPUTE_WH",
      "database": "ANALYTICS"
    },
    "authMethod": "access_key",
    "authConfig": {
      "username": "svc_kaireon",
      "password": "secret"
    }
  }'
```

**Response:** `201 Created` with the connector object (excluding `authConfig`).

***

## PUT /api/v1/connectors

Update an existing connector. Only fields explicitly included in the body
are changed — omitted fields preserve their existing values.

### Request Body

| Field         | Type   | Required | Description                                                                |
| ------------- | ------ | -------- | -------------------------------------------------------------------------- |
| `id`          | string | Yes      | Connector ID                                                               |
| `name`        | string | No       | Updated name                                                               |
| `type`        | string | No       | Updated type                                                               |
| `description` | string | No       | Updated description                                                        |
| `config`      | object | No       | Updated configuration                                                      |
| `authMethod`  | string | No       | Updated auth method                                                        |
| `authConfig`  | object | No       | Updated credentials (re-encrypted). **Omit to keep existing credentials.** |
| `status`      | string | No       | Updated status                                                             |

**Response:** `200 OK` with the updated connector (`authConfig` returned masked).

### Credential preservation contract

`authConfig` is special. The endpoint follows these rules:

* **Omit `authConfig` entirely** → existing credentials are preserved unchanged.
  This is the path used by the UI's Edit form, which leaves credential fields
  blank by default with a "Leave blank to keep existing" placeholder.
* **Send `authConfig` with non-empty values** → new credentials are encrypted
  and stored, replacing the old ones.
* **Send `authConfig: {}`** → existing credentials are wiped. Avoid unless you
  intentionally want to clear them.

Clients implementing connector edit forms should follow the UI pattern: only
serialize `authConfig` into the PUT body when the user actually entered new
credential values.

***

## DELETE /api/v1/connectors

Delete a connector by ID.

### Query Parameters

| Parameter | Type   | Required | Description            |
| --------- | ------ | -------- | ---------------------- |
| `id`      | string | Yes      | Connector ID to delete |

**Response:** `204 No Content`

***

## POST /api/v1/connectors/test

Test a connector's connection by performing a real probe (TCP, HTTP, or SDK-specific check). Rate limited to 100 requests per 60 seconds.

### Request Body

| Field | Type   | Required | Description                 |
| ----- | ------ | -------- | --------------------------- |
| `id`  | string | Yes      | ID of the connector to test |

### Response

```json theme={null}
{
  "id": "conn_001",
  "name": "Production Snowflake",
  "type": "snowflake",
  "status": "active",
  "lastTestedAt": "2026-03-16T14:30:00.000Z",
  "lastError": null,
  "lastSyncRowCount": 18432,
  "lastSyncAt": "2026-03-16T14:30:02.000Z",
  "success": true,
  "verified": true,
  "message": "Connection test succeeded",
  "warning": null,
  "latencyMs": 412
}
```

The test endpoint:

* Validates required configuration fields for the connector type
* Performs a real connection probe where one exists (TCP for databases, HTTP HEAD for REST/webhook, bucket checks for cloud storage, SDK-specific probes for Databricks and Amazon Kinesis). **Not every type has one** — see `verified` below.
* Updates the connector's `status` to `"active"` (verified success), `"unverified"` (config valid but no real probe ran), or `"error"` (failure)
* Uses a circuit breaker to prevent hammering failed connectors
* Includes SSRF protection (blocks private IPs, validates DNS resolution)
* Omits `authConfig` from the response (credentials never leave the server)
* On a **verified** success, stamps `lastSyncAt` with the probe timestamp (`lastSyncRowCount` is populated separately by the pipeline runtime when the connector is used as a source — the test probe itself does not read rows)

### Response Fields

| Field          | Type           | Meaning                                                                                                                                                                                                                                                                                                                                          |
| -------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `success`      | boolean        | `true` when nothing was found to be broken — config validated and, if a probe exists, it passed                                                                                                                                                                                                                                                  |
| `verified`     | boolean        | `true` only when a real network/credential probe actually ran and passed. `false` when the connector type has no probe implemented (e.g. `salesforce`, `hubspot`), or a host-dependent probe (BigQuery) had no reachable host to check — in that case `success` is still `true` (config is valid) but the connection has **not been confirmed**. |
| `message`      | string         | Human-readable summary — `"Connection test succeeded"` when `verified: true`; an explicit "configuration validated, not verified" message when `success: true` but `verified: false`; the failure reason otherwise                                                                                                                               |
| `warning`      | string \| null | Transient informational message when `success: true` but the probe found a soft signal (e.g. an S3 bucket that's reachable but has no files at the prefix yet). **Not persisted** — fresh every call.                                                                                                                                            |
| `latencyMs`    | number         | Round-trip latency for the probe                                                                                                                                                                                                                                                                                                                 |
| `lastError`    | string \| null | **Cleared to `null` on success.** Only set when the probe actually failed. Persisted to the connector row so the detail page can show recent error history.                                                                                                                                                                                      |
| `status`       | string         | `"active"` on a verified success, `"unverified"` on an unverified success, `"error"` on failure — persisted                                                                                                                                                                                                                                      |
| `lastTestedAt` | string         | ISO timestamp of this probe — persisted                                                                                                                                                                                                                                                                                                          |

<Note>
  **A-02 fix (2026-07-15):** connector types with no real probe (BigQuery
  when no host/account is configured, Salesforce, HubSpot, and any other
  type that falls through to config-only validation) used to report
  `"Connection test succeeded"` and flip `status` to `"active"` without ever
  making a network call. The endpoint now reports `verified: false` and
  leaves `status` at `"unverified"` for these — dashboards and pipeline
  gating that key off `status === "active"` no longer count an unverified
  connector as confirmed working.
</Note>

<Note>
  Earlier versions of this endpoint wrote warning text into `lastError` even
  when the test succeeded, which caused UI surfaces to render a persistent
  "Last Error" card despite a green success toast. The endpoint now keeps
  `lastError` reserved for real failures; soft signals travel in the
  transient `warning` field instead. UI clients should suppress red error
  styling when `status === "active"`.
</Note>

<Note>
  Connection testing for the coming-soon `braze` connector reports a
  generic failure until a dedicated probe is wired. **Amazon Kinesis**
  has a working test probe today.
</Note>

### Error Responses

| Status | Cause                        |
| ------ | ---------------------------- |
| `400`  | Missing `id` or invalid JSON |
| `404`  | Connector not found          |
| `429`  | Rate limit exceeded          |

***

## POST /api/v1/connectors/yaml

Register a YAML connector spec. The server runs `parseConnectorYaml` and, on
success, registers the spec in the in-process connector registry.

<Note>
  The YAML registry is **in-memory / process-local** — registered specs are not
  persisted to the database and are re-derived on each server start. This
  endpoint powers custom-connector authoring surfaces, not durable connector
  storage.
</Note>

### Request Body

| Field  | Type   | Required | Description                         |
| ------ | ------ | -------- | ----------------------------------- |
| `yaml` | string | Yes      | The connector spec as a YAML string |

### Response

`201 Created`:

```json theme={null}
{ "ok": true, "id": "my_connector", "displayName": "My Connector", "category": "api" }
```

### Error Responses

| Status | Body                               | Cause                                                      |
| ------ | ---------------------------------- | ---------------------------------------------------------- |
| `400`  | `{ "ok": false, "errors": [...] }` | Missing `yaml` field, or the spec failed to parse/validate |
| `409`  | `{ "ok": false, "errors": [...] }` | A connector with the same id is already registered         |

***

## GET /api/v1/connectors/yaml

List all registered YAML connectors. Returns a bare array (no pagination envelope).

### Response

`200 OK`:

```json theme={null}
[
  { "id": "my_connector", "displayName": "My Connector", "category": "api", "kind": "yaml" }
]
```

***

## Roles

| Endpoint                | Allowed Roles         |
| ----------------------- | --------------------- |
| `GET /connectors`       | admin, editor, viewer |
| `POST /connectors`      | admin, editor         |
| `PUT /connectors`       | admin, editor         |
| `DELETE /connectors`    | admin, editor         |
| `POST /connectors/test` | admin, editor         |
| `POST /connectors/yaml` | admin, editor         |
| `GET /connectors/yaml`  | admin, editor, viewer |

See also: [Data Platform](/data/overview)
