Skip to main content

Data Sources

Manage external data source connections such as databases, cloud storage, and data warehouses. Register, test, and share data source connections across your organization.

All endpoints require a valid API key with the appropriate datasources:* scope.

Base URL: https://<your-instance>/api/v1


DataSource Object​

{
"_id": "ds_abc123",
"name": "production-postgres",
"label": "Production PostgreSQL",
"description": "Main production database for user records",
"type": "postgres",
"category": "relational",
"status": "connected",
"testConnection": {
"lastTested": "2025-01-18T16:30:00Z",
"success": true,
"message": "Connection successful"
},
"metadata": {
"tables": ["users", "orders", "products"],
"schemas": ["public"],
"databases": ["app_db"],
"buckets": [],
"size": 104857600,
"rowCount": 250000
},
"owner": "user_001",
"organizationId": "org_xyz789",
"tags": ["production"],
"permissions": {
"isPublic": false,
"allowAllUsers": false,
"allowedUsers": ["user_002", "user_003"]
},
"usageCount": 12,
"createdAt": "2025-01-10T08:00:00Z",
"updatedAt": "2025-01-18T16:30:00Z"
}
  • owner is the id of the user who registered the data source.
  • category is set from the type (for example relational for postgres).
  • status is connected or error from the connection test run when the data source is created or its credentials change; testConnection holds that test's result.
  • metadata is present once metadata has been fetched with the metadata endpoint; size and rowCount are null where the store has no such measure.

Note: The credentials field is never included in standard responses. Use the dedicated credentials endpoint to retrieve connection credentials.


GET /api/v1/data-sources​

List all data sources accessible to the authenticated user.

Scope: datasources:read

Query Parameters​

ParameterTypeRequiredDefaultDescription
qstringNo--Search by name, label, or description
typestringNo--Filter by type, one of the data source types; all means no filter
categorystringNo--Filter by category: relational, document, key-value, graph, vector, multi-model, spreadsheet, cloud-storage, message-queue, api; all means no filter
statusstringNo--Filter by status: connected, disconnected, error
limitintegerNo50Maximum number of results to return (1-200)
cursorstringNometa.nextCursor of the previous page; omit for the first page
sortstringNo-createdAtSort field, prefix with - for descending, e.g. name, -updatedAt

Response 200 OK​

{
"data": [
{
"_id": "ds_abc123",
"name": "production-postgres",
"label": "Production PostgreSQL",
"description": "Main production database for user records",
"type": "postgres",
"category": "relational",
"status": "connected",
"testConnection": {
"lastTested": "2025-01-18T16:30:00Z",
"success": true,
"message": "Connection successful"
},
"owner": "user_001",
"organizationId": "org_xyz789",
"tags": [],
"permissions": {
"isPublic": false,
"allowAllUsers": false,
"allowedUsers": ["user_002"]
},
"usageCount": 0,
"createdAt": "2025-01-10T08:00:00Z",
"updatedAt": "2025-01-18T16:30:00Z"
}
],
"meta": {
"total": 15,
"limit": 50,
"nextCursor": null,
"requestId": "req_abc123"
}
}

POST /api/v1/data-sources​

Register a new external data source connection.

Scope: datasources:write

Request Body​

FieldTypeRequiredDescription
namestringYesIdentifier name; must not match another data source you own (in your organization)
labelstringYesHuman-readable display name
typestringYesOne of the data source types
credentialsobjectYesConnection credentials; the fields depend on the type (see examples below)
descriptionstringNoDescription of the data source
tagsstring[]NoTags (default: [])

No other fields are accepted: an unknown field (for example category or metadata) returns 400 validation-error. category is set from type.

The platform tests the connection before saving. The data source is created either way: with status connected if the test passed, or error if it failed (testConnection.message says why).

Data Source Types​

type is one of: mysql, postgres, mssql, oracle, redshift, snowflake, bigquery, cockroachdb, cratedb, timescaledb, questdb, clickhouse, singlestore, greenplum, mongodb, elasticsearch, dynamodb, firestore, supabase, couchdb, couchbase, redis, memcached, neo4j, neptune, arangodb, tigergraph, milvus, pinecone, weaviate, qdrant, chroma, pgvector, vespa, marqo, surrealdb, airtable, google-sheets, baserow, nocodb, seatable, grist, s3, gcs, minio, azure-blob, rabbitmq, kafka, sqs, pulsar, mqtt, api.

Categories, set from the type: relational, document, key-value, graph, vector, multi-model, spreadsheet, cloud-storage, message-queue, api.

Database credentials example:

{
"name": "analytics-mysql",
"label": "Analytics MySQL",
"type": "mysql",
"credentials": {
"host": "db.example.com",
"port": 3306,
"username": "analytics_reader",
"password": "secure-password-here",
"database": "analytics"
},
"description": "Read-only MySQL connection for analytics queries",
"tags": ["analytics"]
}

S3 credentials example:

{
"name": "data-lake-s3",
"label": "Data Lake S3",
"type": "s3",
"credentials": {
"bucketName": "my-data-lake",
"region": "us-east-1",
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
},
"description": "S3 bucket for raw data ingestion"
}

Snowflake credentials example:

{
"name": "warehouse-snowflake",
"label": "Snowflake Warehouse",
"type": "snowflake",
"credentials": {
"account": "xy12345.us-east-1",
"username": "ETL_USER",
"password": "secure-password-here",
"warehouse": "COMPUTE_WH",
"database": "ANALYTICS",
"schema": "PUBLIC"
},
"description": "Snowflake data warehouse for reporting"
}

Response 201 Created​

The new data source, without its credentials.

Errors: 400 validation-error for a missing required field (listed in details), a type not in the list, or an unknown field; 409 duplicate if you already have a data source with this name; 403 governance-blocked if the organization's governance requirements for data sources are not met.


GET /api/v1/data-sources/:id​

Retrieve a single data source by its ID. Credentials are excluded from the response.

Scope: datasources:read

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Response 200 OK​

{
"data": {
"_id": "ds_abc123",
"name": "production-postgres",
"label": "Production PostgreSQL",
"description": "Main production database for user records",
"type": "postgres",
"category": "relational",
"status": "connected",
"testConnection": {
"lastTested": "2025-01-18T16:30:00Z",
"success": true,
"message": "Connection successful"
},
"metadata": {
"tables": ["users", "orders", "products"],
"schemas": ["public"],
"databases": ["app_db"],
"buckets": [],
"size": 104857600,
"rowCount": 250000
},
"owner": "user_001",
"organizationId": "org_xyz789",
"tags": ["production"],
"permissions": {
"isPublic": false,
"allowAllUsers": false,
"allowedUsers": ["user_002", "user_003"]
},
"usageCount": 12,
"createdAt": "2025-01-10T08:00:00Z",
"updatedAt": "2025-01-18T16:30:00Z"
},
"meta": {
"requestId": "req_abc123"
}
}

PATCH /api/v1/data-sources/:id​

Update an existing data source. Only provided fields are updated. The type cannot be changed after creation.

Scope: datasources:write

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Request Body​

FieldTypeRequiredDescription
namestringNoUpdated identifier name
labelstringNoUpdated display name
credentialsobjectNoReplacement connection credentials (the whole object, for the data source's type); the connection is tested again and status updated
descriptionstringNoUpdated description
tagsstring[]NoReplacement tag list

No other fields are accepted: an unknown field (including type, category or metadata) returns 400 validation-error.

{
"label": "Production PostgreSQL (Primary)",
"credentials": {
"host": "db-primary.example.com",
"port": 5432,
"username": "app_user",
"password": "new-secure-password",
"database": "app_db"
},
"description": "Updated primary production database connection"
}

Response 200 OK​

The updated data source, without its credentials.

Errors: 400 validation-error for an unknown field; 404 not-found if the data source does not exist; 403 forbidden if you cannot edit it.


DELETE /api/v1/data-sources/:id​

Permanently delete a data source registration. This does not affect the external data source itself, only the connection record on the platform.

Scope: datasources:write

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Response 204 No Content​

No response body.


POST /api/v1/data-sources/:id/test​

Test the connection to the external data source using the stored credentials. Returns the connectivity status and any error details.

Scope: datasources:read

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Response 200 OK (success)​

{
"data": {
"success": true,
"message": "Connection successful"
},
"meta": {
"requestId": "req_abc123"
}
}

Response 200 OK (failure)​

{
"data": {
"success": false,
"message": "Connection refused: host db.example.com port 5432"
},
"meta": {
"requestId": "req_abc123"
}
}

GET /api/v1/data-sources/:id/metadata​

Retrieve what the data source holds: databases, schemas, tables or collections, buckets, indexes or topics, with sizes and row counts where the system reports them. A table's columns come from table-columns; a bucket's files from objects. An api key and an mqtt broker hold no catalogue and have no metadata.

Scope: datasources:read

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Response 200 OK (database example)​

{
"data": {
"tables": ["orders", "users"],
"schemas": ["public"],
"databases": ["app_db"],
"buckets": [],
"size": 52428800,
"rowCount": 99630
},
"meta": {
"requestId": "req_abc123"
}
}

Response 200 OK (S3 example)​

{
"data": {
"tables": [],
"schemas": [],
"databases": [],
"buckets": ["my-data-lake"],
"size": 5368709120,
"rowCount": 12450
},
"meta": {
"requestId": "req_abc123"
}
}

GET /api/v1/data-sources/:id/status​

The data source's last known health, read-only (use POST /data-sources/:id/test to probe it now): its status and the time and, when it failed, the message of its last connection test. A data source that was never tested has null for both.

Scope: datasources:read

Response 200 OK​

{
"data": {
"datasourceId": "ds_abc123",
"status": "error",
"lastTestedAt": "2026-10-10T12:00:00.000Z",
"lastError": "connection refused",
"type": "postgres",
"updatedAt": "2026-10-10T12:00:00.000Z"
},
"meta": {
"requestId": "req_abc123"
}
}

status is connected (last test passed), error (last test failed), testing, or disconnected (never tested).


GET /api/v1/data-sources/:id/table-columns​

Describe one table of the data source: its columns (name, type, nullable, key), row count and size. "Table" is what the type holds: a SQL table, a collection, an index, a sheet, a node label, a queue or topic, a Redis key pattern. A collection whose store declares no schema is described from a sample of its documents (sampled gives how many). Every type except object storage (use objects) and API keys.

Scope: datasources:read

Query Parameters​

ParameterTypeRequiredDescription
tablestringYesThe table as metadata lists it (schema.table outside the default schema)
schemastringNoA schema or namespace, for example public

Response 200 OK​

{
"data": {
"datasourceId": "ds_abc123",
"table": "orders",
"schema": null,
"columns": {
"columns": [
{ "name": "id", "type": "integer", "nullable": false, "key": "PRIMARY" },
{ "name": "status", "type": "text", "nullable": true, "key": null }
],
"rowCount": 99630,
"size": 52428800
}
},
"meta": {
"requestId": "req_abc123"
}
}

GET /api/v1/data-sources/:id/objects​

List the files and folders at one level of an object-storage data source (s3, minio, gcs, azure-blob). Pass prefix to descend into a folder; keys are relative to it.

Scope: datasources:read

Query Parameters​

ParameterTypeRequiredDescription
bucketstringNoThe bucket (container) to list; the data source's own bucket when omitted
prefixstringNoThe folder to list, for example exports/

Response 200 OK​

{
"data": {
"bucket": "my-data-lake",
"prefix": "exports/",
"contents": [
{ "key": "2026/", "size": 0, "lastModified": null, "isFolder": true },
{ "key": "orders.csv", "size": 18342, "lastModified": "2026-10-09T08:15:00.000Z", "isFolder": false }
]
},
"meta": {
"requestId": "req_abc123"
}
}

GET /api/v1/data-sources/:id/credentials​

Retrieve the stored connection credentials for a data source. Handle the response securely and avoid logging credential values.

Scope: datasources:read

Path Parameters​

ParameterTypeRequiredDescription
idstringYesThe data source ID

Response 200 OK (database)​

{
"data": {
"host": "db.example.com",
"port": 5432,
"username": "app_user",
"password": "secure-password-here",
"database": "app_db"
},
"meta": {
"requestId": "req_abc123"
}
}

Response 200 OK (S3)​

{
"data": {
"accessKeyId": "AKIAIOSFODNN7EXAMPLE",
"secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"region": "us-east-1",
"bucket": "my-data-lake"
},
"meta": {
"requestId": "req_abc123"
}
}

Sharing​

Who can reach a data source is the platform's one sharing shape: its owner, its members (role editor can use and change it, user can only use it) and its visibility (public: every user can find and use it; in a multi-tenant deployment, every user of its organization). Changing it stays with its owner and editors.

MethodPathDoesScope
GET/api/v1/data-sources/:id/permissionsOwner, members (userId, role) and visibilitydatasources:read
POST/api/v1/data-sources/:id/permissions/membersShare with a user: { "userId", "role": "editor" | "user" }datasources:write
DELETE/api/v1/data-sources/:dataSourceId/permissions/members/:userIdStop sharing with a userdatasources:write
PATCH/api/v1/data-sources/:id/permissions{ "visibility": "public" | "private" }datasources:write

Each, except a member's removal (204), answers the permissions as they are now:

{
"data": {
"resourceId": "<data source id>",
"owner": "<user id>",
"members": [{ "userId": "<user id>", "role": "user" }],
"visibility": "private"
},
"meta": { "requestId": "req_abc123" }
}

Error Responses​

All endpoints may return the following error responses:

StatusDescription
400 Bad RequestInvalid request body or parameters, or a share with someone who cannot receive it (such as yourself)
401 UnauthorizedMissing or invalid API key
403 ForbiddenInsufficient scope for the requested operation
404 Not FoundData source not found or not accessible
409 ConflictData source name already exists in the organization
422 Unprocessable EntityValidation error on request body
429 Too Many RequestsRate limit exceeded
500 Internal Server ErrorUnexpected server error
{
"type": "urn:strongly:problem:validation-error",
"title": "Validation failed",
"status": 400,
"detail": "Missing required fields",
"code": "validation-error",
"requestId": "req_abc123",
"errors": [
{ "field": "credentials", "message": "credentials is required", "type": "required" }
]
}