Skip to content

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.

https://api.querri.com/api

All Connectors API endpoints require JWT authentication. See Authentication for details.

Querri supports two main connector categories:

Authentication via OAuth 2.0 flow:

  • Google BigQuery
  • Snowflake
  • Salesforce
  • HubSpot
  • Stripe
  • Google Analytics
  • Microsoft Azure

Authentication via credentials or API keys:

  • PostgreSQL
  • MySQL
  • MongoDB
  • Redis
  • Amazon Redshift
  • Databricks
  • REST API (generic)

Retrieve all available connector types and user’s active connectors.

GET /api/connectors

Query Parameters:

ParameterTypeDefaultDescription
typestring-Filter by connector type
statusstring-Filter by status: active, disabled, error
include_availablebooleantrueInclude available (not configured) connector types

Example Request:

Terminal window
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 a new connector using direct credentials (non-OAuth).

POST /api/connectors

Headers:

Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json

Request 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:

FieldTypeRequiredDescription
typestringYesConnector type identifier
display_namestringYesHuman-readable name
configobjectYesType-specific configuration
test_connectionbooleanNoTest 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"
}

Initiate OAuth authorization flow for OAuth-based connectors.

GET /api/oauth/{provider}/authorize

Path Parameters:

ParameterTypeDescription
providerstringOAuth provider: bigquery, snowflake, salesforce, etc.

Query Parameters:

ParameterTypeRequiredDescription
redirect_uristringNoCustom redirect URI (must be whitelisted)
statestringYesCSRF protection state parameter
display_namestringNoPre-fill display name

Example Request:

Terminal window
# User is redirected to this URL in browser
https://api.querri.com/api/oauth/snowflake/authorize?state=random_csrf_token_123&display_name=Snowflake%20DW

Response: 302 Redirect

Redirects to provider’s OAuth authorization page:

Location: https://snowflake.okta.com/oauth/authorize?client_id=...&redirect_uri=...&state=...

Handle OAuth callback and create connector.

GET /api/oauth/{provider}/callback

Query Parameters:

ParameterTypeDescription
codestringAuthorization code from provider
statestringCSRF 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=success

Error Response:

Location: https://app.querri.com/connectors?error=authorization_failed&message=User%20denied%20access

Manually refresh an OAuth connector’s access token.

POST /api/oauth/{provider}/refresh

Request 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 configuration or display name.

PATCH /api/connectors/{uuid}

Headers:

Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json

Request 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 a connector permanently.

DELETE /api/connectors/{uuid}

Query Parameters:

ParameterTypeDefaultDescription
forcebooleanfalseForce delete even if in use

Example Request:

Terminal window
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}
]
}

Temporarily disable a connector without deleting.

POST /api/connectors/{uuid}/disable

Request 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:

Terminal window
curl -X POST "https://api.querri.com/api/connectors/conn_01ABCDEF/enable" \
-H "Authorization: Bearer ${JWT_TOKEN}"

Test connectivity and credentials for an existing connector.

POST /api/connectors/{uuid}/test

Response: 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"
}
}

{
"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)"
}
}
{
"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"
}
}
{
"type": "snowflake",
"config": {
"account": "string (required) - account identifier",
"warehouse": "string (required)",
"database": "string (required)",
"schema": "string (default: PUBLIC)",
"role": "string (optional)"
}
}
{
"type": "bigquery",
"config": {
"project_id": "string (required)",
"dataset": "string (optional - default dataset)",
"location": "string (default: US)"
}
}
{
"type": "salesforce",
"config": {
"instance_url": "string (auto-populated)",
"api_version": "string (default: v59.0)",
"sandbox": "boolean (default: false)"
}
}
{
"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)"
}
}

Connectors use OpenFGA for fine-grained access control:

LevelCapabilities
ownerFull control: edit, delete, share
editorUse connector, update configuration
viewerRead-only: view config (credentials hidden), test connection
Terminal window
# Grant access to another user
curl -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.


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
{
"config": {
"max_connections": 10,
"connection_timeout_seconds": 30,
"idle_timeout_seconds": 600,
"statement_timeout_seconds": 300
}
}

  1. Rotate Credentials Regularly - Update passwords and API keys quarterly
  2. Use OAuth When Available - Preferred over storing credentials
  3. Enable SSL/TLS - Always use encrypted connections
  4. Principle of Least Privilege - Grant minimal required permissions
  5. Monitor Connection Activity - Review connector usage regularly
  6. Test After Updates - Always test connections after configuration changes
  7. Use Service Accounts - Dedicated accounts for Querri, not personal accounts

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

Terminal window
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": []
}

Configure webhooks for connector events:

  • connector.connection_failed - Connection test failed
  • connector.credentials_expired - OAuth token expired
  • connector.quota_exceeded - API rate limit reached

See Webhooks API.


CodeDescription
200Success (GET, PATCH, POST test)
201Created (POST connector)
204No Content (DELETE)
302Redirect (OAuth flow)
400Bad Request (validation error, connection failed)
401Unauthorized
403Forbidden (insufficient permissions)
404Not Found
409Conflict (connector in use)
429Too Many Requests
500Internal Server Error