API Reference¶
The Dashforge REST API provides programmatic access to dashboards, data sources, and queries.
Base URL¶
Authentication¶
Most endpoints require authentication via JWT Bearer token:
Response Format¶
All responses use JSON:
Error responses:
Endpoints¶
Health¶
Check Health¶
No authentication required.
Response:
Authentication¶
See Authentication for detailed OAuth flow documentation.
Get Current User¶
Response:
{
"id": 1,
"email": "user@example.com",
"name": "John Doe",
"role": "admin",
"active": true,
"lastLoginAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z"
}
Refresh Token¶
Request:
Response:
{
"accessToken": "new-access-token",
"refreshToken": "new-refresh-token",
"expiresIn": 900,
"tokenType": "Bearer"
}
Dashboards¶
List Dashboards¶
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| page | int | Page number (default: 1) |
| perPage | int | Items per page (default: 20, max: 100) |
| search | string | Search title/description |
| sort | string | Sort field (created_at, updated_at, title) |
| order | string | Sort order (asc, desc) |
Response:
{
"data": [
{
"id": 1,
"slug": "sales-dashboard",
"title": "Sales Dashboard",
"description": "Monthly sales metrics",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"meta": {
"total": 42,
"page": 1,
"perPage": 20
}
}
Get Dashboard¶
Response:
{
"id": 1,
"slug": "sales-dashboard",
"title": "Sales Dashboard",
"description": "Monthly sales metrics",
"definition": {
"layout": { ... },
"dataSources": [ ... ],
"widgets": [ ... ]
},
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
Create Dashboard¶
Request:
{
"slug": "new-dashboard",
"title": "New Dashboard",
"description": "Optional description",
"definition": {
"layout": {
"type": "grid",
"columns": 12,
"rowHeight": 80
},
"dataSources": [],
"widgets": []
}
}
Response: 201 Created
{
"id": 2,
"slug": "new-dashboard",
"title": "New Dashboard",
"createdAt": "2024-01-15T12:00:00Z",
"updatedAt": "2024-01-15T12:00:00Z"
}
Update Dashboard¶
Request:
Response: 200 OK
Delete Dashboard¶
Response: 204 No Content
Data Sources¶
External database connections for querying. See Data Sources for concepts.
List Providers¶
No authentication required.
Response:
{
"providers": [
{
"name": "postgres",
"capabilities": {
"supportsTransactions": true,
"supportsStreaming": true,
"supportsPreparedStmts": true,
"supportsNamedParams": false,
"parameterStyle": "positional_dollar"
}
},
{
"name": "mysql",
"capabilities": {
"supportsTransactions": true,
"supportsStreaming": true,
"supportsPreparedStmts": true,
"supportsNamedParams": false,
"parameterStyle": "positional_question"
}
}
]
}
List Data Sources¶
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| active | bool | Filter by active status |
| type | string | Filter by provider type (postgres, mysql) |
Response:
{
"dataSources": [
{
"id": 1,
"name": "Production DB",
"slug": "prod-db",
"type": "postgres",
"maxConnections": 10,
"queryTimeoutSeconds": 30,
"readOnly": true,
"sslEnabled": true,
"active": true,
"lastConnectedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
],
"total": 1
}
Secrets Excluded
Connection URLs are never returned in list/get responses for security.
Get Data Source¶
Response:
{
"id": 1,
"name": "Production DB",
"slug": "prod-db",
"type": "postgres",
"maxConnections": 10,
"queryTimeoutSeconds": 30,
"readOnly": true,
"sslEnabled": true,
"active": true,
"connectionUrlEnv": "PROD_DATABASE_URL",
"lastConnectedAt": "2024-01-15T10:30:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-15T10:30:00Z"
}
Create Data Source¶
Request:
{
"name": "Analytics DB",
"slug": "analytics-db",
"type": "postgres",
"connectionUrl": "postgres://user:pass@db.example.com:5432/analytics?sslmode=require",
"maxConnections": 10,
"queryTimeoutSeconds": 30,
"readOnly": true,
"sslEnabled": true,
"active": true
}
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Display name |
| slug | string | Yes | URL-safe identifier (unique) |
| type | string | Yes | Provider type (postgres, mysql) |
| connectionUrl | string | * | Connection string |
| connectionUrlEnv | string | * | Env var containing connection URL |
| maxConnections | int | No | Max pool size (default: 10) |
| queryTimeoutSeconds | int | No | Query timeout (default: 30) |
| readOnly | bool | No | Restrict to SELECT queries |
| sslEnabled | bool | No | Enable SSL/TLS |
| active | bool | No | Enable data source |
*Either connectionUrl or connectionUrlEnv is required.
Response: 201 Created
{
"id": 2,
"name": "Analytics DB",
"slug": "analytics-db",
"type": "postgres",
"active": true,
"createdAt": "2024-01-15T12:00:00Z"
}
Update Data Source¶
Request:
{
"name": "Updated Name",
"connectionUrl": "postgres://newurl...",
"maxConnections": 20,
"active": false
}
All fields are optional. Only provided fields are updated.
Response: 200 OK
Delete Data Source¶
Closes any active connections before deleting.
Response: 204 No Content
Test Connection¶
Tests the connection without caching. Updates lastConnectedAt on success.
Response:
On failure:
Execute Query¶
Request:
{
"query": "SELECT date, SUM(amount) as total FROM sales WHERE region = :region GROUP BY date",
"parameters": {
"region": "US"
},
"maxRows": 1000
}
| Field | Type | Required | Description |
|---|---|---|---|
| query | string | Yes | SQL query |
| parameters | object | No | Named parameters (:name or @name) |
| maxRows | int | No | Max rows to return (default: 1000, max: 10000) |
Response:
{
"columns": [
{"name": "date", "type": "DATE", "nullable": false},
{"name": "total", "type": "NUMERIC", "nullable": true, "precision": 10, "scale": 2}
],
"rows": [
{"date": "2024-01-01", "total": 15000.50},
{"date": "2024-01-02", "total": 18500.75}
],
"rowCount": 2,
"executionTimeMs": 125
}
Read-Only Data Sources
If the data source has readOnly: true, only SELECT queries are allowed. INSERT/UPDATE/DELETE will return a 400 error.
Get Schema¶
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| schema | string | Filter by schema name (default: public/current db) |
| columns | bool | Include column details |
| filter | string | Filter tables by name pattern |
Response:
{
"tables": [
{
"schema": "public",
"name": "sales",
"type": "table",
"columns": [
{"name": "id", "type": "INTEGER", "nullable": false},
{"name": "date", "type": "DATE", "nullable": false},
{"name": "amount", "type": "NUMERIC", "nullable": true, "precision": 10, "scale": 2},
{"name": "region", "type": "VARCHAR", "nullable": true, "length": 50}
]
},
{
"schema": "public",
"name": "sales_summary",
"type": "view"
}
]
}
Queries¶
Execute Query¶
Request:
{
"dataSourceId": 1,
"query": "SELECT date, SUM(amount) as total FROM sales GROUP BY date",
"params": {
"limit": 100
}
}
Response:
{
"columns": ["date", "total"],
"rows": [
{ "date": "2024-01-01", "total": 15000 },
{ "date": "2024-01-02", "total": 18500 }
],
"rowCount": 2,
"executionTimeMs": 125
}
List Saved Queries¶
Save Query¶
Request:
{
"name": "Monthly Revenue",
"description": "Total revenue by month",
"dataSourceId": 1,
"query": "SELECT DATE_TRUNC('month', created_at) as month, SUM(amount) as revenue FROM orders GROUP BY 1"
}
Run Saved Query¶
Request:
Users (Admin)¶
Requires admin or owner role.
List Users¶
Create User¶
Request:
Update User Role¶
Request:
Deactivate User¶
Tenants (Admin)¶
Requires owner role.
List Tenants¶
Create Tenant¶
Request:
Error Codes¶
| Code | HTTP Status | Description |
|---|---|---|
| UNAUTHORIZED | 401 | Missing or invalid authentication |
| FORBIDDEN | 403 | Insufficient permissions |
| NOT_FOUND | 404 | Resource not found |
| VALIDATION_ERROR | 400 | Invalid request data |
| CONFLICT | 409 | Resource already exists |
| RATE_LIMITED | 429 | Too many requests |
| INTERNAL_ERROR | 500 | Server error |
Rate Limiting¶
API requests are rate limited:
| Tier | Requests/minute |
|---|---|
| Free | 60 |
| Pro | 300 |
| Enterprise | 1000 |
Rate limit headers:
Pagination¶
List endpoints support pagination:
Response includes meta: