Connectors API
The Connectors API enables integration with databases, APIs, and third-party services. Connectors provide authenticated access to external data sources for use in projects and steps.
Base URL
Section titled “Base URL”https://api.querri.com/apiAuthentication
Section titled “Authentication”All Connectors API endpoints require JWT authentication. See Authentication for details.
Connector Types
Section titled “Connector Types”Querri supports two main connector categories:
OAuth Connectors
Section titled “OAuth Connectors”Authentication via OAuth 2.0 flow:
- Google BigQuery
- Snowflake
- Salesforce
- HubSpot
- Stripe
- Google Analytics
- Microsoft Azure
Direct Connectors
Section titled “Direct Connectors”Authentication via credentials or API keys:
- PostgreSQL
- MySQL
- MongoDB
- Redis
- Amazon Redshift
- Databricks
- REST API (generic)
Endpoints
Section titled “Endpoints”List Connectors
Section titled “List Connectors”Retrieve all available connector types and user’s active connectors.
GET /api/connectorsQuery Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
type | string | - | Filter by connector type |
status | string | - | Filter by status: active, disabled, error |
include_available | boolean | true | Include available (not configured) connector types |
Example Request:
curl "https://api.querri.com/api/connectors?include_available=true" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."Response: 200 OK
{ "active_connectors": [ { "uuid": "conn_01ABCDEF", "type": "postgresql", "display_name": "Production Database", "config": { "host": "db.example.com", "port": 5432, "database": "production", "username": "querri_user", "ssl_enabled": true }, "status": "active", "created_by": "user_01ABCDEF", "created_at": "2025-01-10T10:00:00Z", "last_tested_at": "2025-01-15T09:00:00Z", "last_test_status": "success", "permissions": { "can_edit": true, "can_delete": true, "can_share": true } }, { "uuid": "conn_02GHIJKL", "type": "snowflake", "display_name": "Snowflake Data Warehouse", "config": { "account": "xy12345.us-east-1", "warehouse": "COMPUTE_WH", "database": "ANALYTICS", "schema": "PUBLIC" }, "auth_type": "oauth", "status": "active", "created_at": "2025-01-12T14:00:00Z", "last_tested_at": "2025-01-15T09:00:00Z", "last_test_status": "success" } ], "available_types": [ { "type": "bigquery", "name": "Google BigQuery", "description": "Google Cloud data warehouse", "category": "data_warehouse", "auth_type": "oauth", "features": ["sql_query", "streaming", "partitioning"], "documentation_url": "https://docs.querri.com/connectors/bigquery" }, { "type": "mysql", "name": "MySQL", "description": "MySQL database server", "category": "database", "auth_type": "credentials", "features": ["sql_query"], "documentation_url": "https://docs.querri.com/connectors/mysql" } ], "total_active": 2, "total_available": 24}Create Connector (Direct Auth)
Section titled “Create Connector (Direct Auth)”Create a new connector using direct credentials (non-OAuth).
POST /api/connectorsHeaders:
Authorization: Bearer {JWT_TOKEN}Content-Type: application/jsonRequest Body (PostgreSQL Example):
{ "type": "postgresql", "display_name": "Production Database", "config": { "host": "db.example.com", "port": 5432, "database": "production", "username": "querri_user", "password": "secure_password_123", "ssl_enabled": true, "ssl_mode": "require" }, "test_connection": true}Request Body (MongoDB Example):
{ "type": "mongodb", "display_name": "MongoDB Cluster", "config": { "connection_string": "mongodb+srv://user:pass@cluster.mongodb.net/", "database": "analytics", "auth_source": "admin" }, "test_connection": true}Request Body (REST API Example):
{ "type": "rest_api", "display_name": "Internal API", "config": { "base_url": "https://api.internal.com", "auth_type": "bearer", "auth_token": "sk_live_abc123...", "headers": { "X-API-Version": "2024-01-15" }, "timeout_seconds": 30 }, "test_connection": true}Common Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Connector type identifier |
display_name | string | Yes | Human-readable name |
config | object | Yes | Type-specific configuration |
test_connection | boolean | No | Test connection before creating (default: true) |
Response: 201 Created
{ "uuid": "conn_01ABCDEF", "type": "postgresql", "display_name": "Production Database", "config": { "host": "db.example.com", "port": 5432, "database": "production", "username": "querri_user", "ssl_enabled": true, "ssl_mode": "require" }, "status": "active", "created_by": "user_01ABCDEF", "created_at": "2025-01-15T10:00:00Z", "last_tested_at": "2025-01-15T10:00:00Z", "last_test_status": "success", "test_results": { "latency_ms": 45, "version": "PostgreSQL 15.2" }}Error Responses:
// 400 Bad Request - Connection test failed{ "error": "connection_failed", "message": "Failed to connect to database", "details": "Connection refused at db.example.com:5432", "test_results": { "error_type": "connection_refused", "attempted_at": "2025-01-15T10:00:00Z" }}
// 400 Bad Request - Invalid configuration{ "error": "validation_error", "message": "Invalid connector configuration", "field": "config.host", "details": "Host is required for PostgreSQL connectors"}OAuth Flow: Authorize
Section titled “OAuth Flow: Authorize”Initiate OAuth authorization flow for OAuth-based connectors.
GET /api/oauth/{provider}/authorizePath Parameters:
| Parameter | Type | Description |
|---|---|---|
provider | string | OAuth provider: bigquery, snowflake, salesforce, etc. |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
redirect_uri | string | No | Custom redirect URI (must be whitelisted) |
state | string | Yes | CSRF protection state parameter |
display_name | string | No | Pre-fill display name |
Example Request:
# User is redirected to this URL in browserhttps://api.querri.com/api/oauth/snowflake/authorize?state=random_csrf_token_123&display_name=Snowflake%20DWResponse: 302 Redirect
Redirects to provider’s OAuth authorization page:
Location: https://snowflake.okta.com/oauth/authorize?client_id=...&redirect_uri=...&state=...OAuth Flow: Callback
Section titled “OAuth Flow: Callback”Handle OAuth callback and create connector.
GET /api/oauth/{provider}/callbackQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
code | string | Authorization code from provider |
state | string | CSRF state parameter (must match authorize request) |
This endpoint is automatically called by the OAuth provider after user authorization.
Response: 302 Redirect
Redirects to application with connector UUID:
Location: https://app.querri.com/connectors?uuid=conn_02GHIJKL&status=successError Response:
Location: https://app.querri.com/connectors?error=authorization_failed&message=User%20denied%20accessOAuth Flow: Refresh Token
Section titled “OAuth Flow: Refresh Token”Manually refresh an OAuth connector’s access token.
POST /api/oauth/{provider}/refreshRequest Body:
{ "connector_uuid": "conn_02GHIJKL"}Response: 200 OK
{ "connector_uuid": "conn_02GHIJKL", "status": "active", "token_refreshed_at": "2025-01-15T10:30:00Z", "expires_at": "2025-01-15T11:30:00Z"}Note: Token refresh happens automatically before expiration. Manual refresh is rarely needed.
Update Connector
Section titled “Update Connector”Update connector configuration or display name.
PATCH /api/connectors/{uuid}Headers:
Authorization: Bearer {JWT_TOKEN}Content-Type: application/jsonRequest Body:
{ "display_name": "Production DB (Updated)", "config": { "host": "db2.example.com", "port": 5432, "database": "production_v2", "username": "querri_user", "password": "new_secure_password", "ssl_enabled": true, "ssl_mode": "require" }, "test_connection": true}Response: 200 OK
Returns updated connector object.
Permission Required: connector:edit (connector creator or org admin).
Error Responses:
// 409 Conflict - Connector in use{ "error": "conflict", "message": "Cannot update connector while steps are executing", "active_executions": 3}Delete Connector
Section titled “Delete Connector”Delete a connector permanently.
DELETE /api/connectors/{uuid}Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
force | boolean | false | Force delete even if in use |
Example Request:
curl -X DELETE "https://api.querri.com/api/connectors/conn_01ABCDEF" \ -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."Response: 204 No Content
Permission Required: connector:delete (connector creator or org admin).
Error Responses:
// 409 Conflict - Connector in use{ "error": "conflict", "message": "Cannot delete connector: used by 5 projects", "usage": [ {"project_uuid": "proj_01ABCDEF", "project_name": "Sales Analysis", "step_count": 3} ]}Disable Connector
Section titled “Disable Connector”Temporarily disable a connector without deleting.
POST /api/connectors/{uuid}/disableRequest Body:
{ "reason": "Maintenance window"}Response: 200 OK
{ "uuid": "conn_01ABCDEF", "status": "disabled", "disabled_at": "2025-01-15T10:00:00Z", "disabled_by": "user_01ABCDEF", "reason": "Maintenance window"}Re-enable:
curl -X POST "https://api.querri.com/api/connectors/conn_01ABCDEF/enable" \ -H "Authorization: Bearer ${JWT_TOKEN}"Test Connector
Section titled “Test Connector”Test connectivity and credentials for an existing connector.
POST /api/connectors/{uuid}/testResponse: 200 OK
{ "connector_uuid": "conn_01ABCDEF", "status": "success", "tested_at": "2025-01-15T10:00:00Z", "latency_ms": 42, "details": { "version": "PostgreSQL 15.2", "server_time": "2025-01-15T10:00:00Z", "schemas_available": ["public", "analytics", "staging"] }}Error Response:
{ "connector_uuid": "conn_01ABCDEF", "status": "failed", "tested_at": "2025-01-15T10:00:00Z", "error": { "type": "authentication_failed", "message": "Invalid username or password", "code": "28P01" }}Connector Configuration Schemas
Section titled “Connector Configuration Schemas”PostgreSQL
Section titled “PostgreSQL”{ "type": "postgresql", "config": { "host": "string (required)", "port": "integer (default: 5432)", "database": "string (required)", "username": "string (required)", "password": "string (required)", "ssl_enabled": "boolean (default: false)", "ssl_mode": "enum: disable|allow|prefer|require|verify-ca|verify-full", "connection_timeout_seconds": "integer (default: 30)", "max_connections": "integer (default: 5)" }}{ "type": "mysql", "config": { "host": "string (required)", "port": "integer (default: 3306)", "database": "string (required)", "username": "string (required)", "password": "string (required)", "ssl_enabled": "boolean (default: false)", "charset": "string (default: utf8mb4)" }}MongoDB
Section titled “MongoDB”{ "type": "mongodb", "config": { "connection_string": "string (required) - full connection string", "database": "string (required)", "auth_source": "string (default: admin)", "replica_set": "string (optional)", "read_preference": "enum: primary|primaryPreferred|secondary|secondaryPreferred|nearest" }}Snowflake (OAuth)
Section titled “Snowflake (OAuth)”{ "type": "snowflake", "config": { "account": "string (required) - account identifier", "warehouse": "string (required)", "database": "string (required)", "schema": "string (default: PUBLIC)", "role": "string (optional)" }}Google BigQuery (OAuth)
Section titled “Google BigQuery (OAuth)”{ "type": "bigquery", "config": { "project_id": "string (required)", "dataset": "string (optional - default dataset)", "location": "string (default: US)" }}Salesforce (OAuth)
Section titled “Salesforce (OAuth)”{ "type": "salesforce", "config": { "instance_url": "string (auto-populated)", "api_version": "string (default: v59.0)", "sandbox": "boolean (default: false)" }}REST API
Section titled “REST API”{ "type": "rest_api", "config": { "base_url": "string (required)", "auth_type": "enum: none|bearer|basic|api_key|oauth2", "auth_token": "string (if auth_type=bearer)", "api_key_header": "string (if auth_type=api_key)", "api_key_value": "string (if auth_type=api_key)", "username": "string (if auth_type=basic)", "password": "string (if auth_type=basic)", "headers": "object (additional headers)", "timeout_seconds": "integer (default: 30)" }}Connector Permissions
Section titled “Connector Permissions”Connectors use OpenFGA for fine-grained access control:
Permission Levels
Section titled “Permission Levels”| Level | Capabilities |
|---|---|
owner | Full control: edit, delete, share |
editor | Use connector, update configuration |
viewer | Read-only: view config (credentials hidden), test connection |
Sharing Connectors
Section titled “Sharing Connectors”# Grant access to another usercurl -X POST "https://api.querri.com/api/permissions/resource/connector/conn_01ABCDEF" \ -H "Authorization: Bearer ${JWT_TOKEN}" \ -H "Content-Type: application/json" \ -d '{ "user_id": "user_02GHIJKL", "permission": "editor" }'See Permissions API for more details.
Connection Pooling
Section titled “Connection Pooling”Querri automatically manages connection pools for database connectors:
- Pool Size: Configurable per connector (default: 5)
- Idle Timeout: 10 minutes
- Max Lifetime: 1 hour
- Connection Reuse: Automatic across steps
Performance Optimization
Section titled “Performance Optimization”{ "config": { "max_connections": 10, "connection_timeout_seconds": 30, "idle_timeout_seconds": 600, "statement_timeout_seconds": 300 }}Security Best Practices
Section titled “Security Best Practices”- Rotate Credentials Regularly - Update passwords and API keys quarterly
- Use OAuth When Available - Preferred over storing credentials
- Enable SSL/TLS - Always use encrypted connections
- Principle of Least Privilege - Grant minimal required permissions
- Monitor Connection Activity - Review connector usage regularly
- Test After Updates - Always test connections after configuration changes
- Use Service Accounts - Dedicated accounts for Querri, not personal accounts
Credential Storage
Section titled “Credential Storage”All credentials are encrypted at rest using AES-256 encryption:
- Passwords encrypted before database storage
- API keys stored in secure secrets manager (AWS Secrets Manager / Google Secret Manager)
- OAuth tokens refreshed automatically before expiration
- No plaintext credentials in logs or error messages
Connection Status Monitoring
Section titled “Connection Status Monitoring”Connector Health
Section titled “Connector Health”curl "https://api.querri.com/api/connectors/conn_01ABCDEF/health" \ -H "Authorization: Bearer ${JWT_TOKEN}"Response:
{ "connector_uuid": "conn_01ABCDEF", "status": "healthy", "last_check": "2025-01-15T14:55:00Z", "metrics": { "uptime_percentage_24h": 99.9, "average_latency_ms": 45, "error_rate_24h": 0.001, "total_queries_24h": 1523 }, "recent_errors": []}Webhook Notifications
Section titled “Webhook Notifications”Configure webhooks for connector events:
connector.connection_failed- Connection test failedconnector.credentials_expired- OAuth token expiredconnector.quota_exceeded- API rate limit reached
See Webhooks API.
HTTP Status Codes
Section titled “HTTP Status Codes”| Code | Description |
|---|---|
| 200 | Success (GET, PATCH, POST test) |
| 201 | Created (POST connector) |
| 204 | No Content (DELETE) |
| 302 | Redirect (OAuth flow) |
| 400 | Bad Request (validation error, connection failed) |
| 401 | Unauthorized |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found |
| 409 | Conflict (connector in use) |
| 429 | Too Many Requests |
| 500 | Internal Server Error |