# Observability Enhancements Source: https://docs.usedatabrain.com/changelog/observability-release New optional OpenTelemetry support and configurable log levels for self-hosted deployments # New: Observability Enhancements This release adds optional OpenTelemetry support for improved monitoring and configurable log levels for self-hosted Databrain deployments. ## Upgrade Notes **No action required for upgrade** - all defaults maintain current behavior. Your existing deployment will work exactly as before without any configuration changes. ## New Features ### Configurable Log Levels You can now control the verbosity of application logs via the `LOG_LEVEL` environment variable: ```bash theme={"dark"} LOG_LEVEL=info # Default - same as current behavior LOG_LEVEL=debug # Enable detailed debug logs for troubleshooting LOG_LEVEL=warn # Only warnings and errors LOG_LEVEL=error # Only errors ``` ### OpenTelemetry Integration (Optional) Enable comprehensive observability with OpenTelemetry to get: * **API Latency Tracking**: Automatic timing for all endpoints * **Error Rate Metrics**: Monitor application health * **Distributed Tracing**: See exactly where time is spent in each request * **Log Correlation**: Link logs to specific request traces To enable, add these to your `.env`: ```bash theme={"dark"} OTEL_ENABLED=true OTEL_EXPORTER_OTLP_ENDPOINT=http://your-collector:4318 ``` OpenTelemetry data can be exported to any OTLP-compatible backend including: * Grafana (Tempo + Loki + Prometheus) * SigNoz * Jaeger * Datadog * New Relic ## New Environment Variables | Variable | Default | Description | | ----------------------------- | --------------- | ------------------------------------- | | `LOG_LEVEL` | `info` | Log verbosity (debug/info/warn/error) | | `OTEL_ENABLED` | `false` | Enable OpenTelemetry | | `OTEL_EXPORTER_OTLP_ENDPOINT` | - | OTLP collector URL | | `OTEL_SERVICE_NAME` | `databrain-api` | Service name in traces | ## Documentation See the [Observability Setup Guide](/guides/observability-setup) for detailed configuration instructions. # Product changelog Source: https://docs.usedatabrain.com/changelog/product-changelog **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Baselines for Line and Bar Charts:** Users can now add horizontal or vertical baseline lines on the X-axis or Y-axis. Custom baseline and mark line settings for charts ### Enhancements: 1. **Import `DashboardProps` and `MetricProps` from the DataBrain Plugin:** Added ambient declarations to support importing `DashboardProps` and `MetricProps` from the DataBrain Plugin. 2. **Customize Metric Borders in Manage Metrics:** Users can now customize metric borders from Manage Metrics or Gallery. Manage Metrics dialog with searchable metric selection 3. **Wrap Axis Text in Line and Bar Charts:** Added support to wrap text on the horizontal or vertical axis for line and bar charts. Wrap Text setting for X-axis labels 4. **[Export Dashboard API](/developer-docs/helpers/api-reference/export-dashboard):** `workspaceName` is now optional in the Export Dashboard API. 5. **Guest Token API: [Hide Selected Dashboard Metrics](/developer-docs/helpers/api-reference/token) for Embedded Clients:** Added a new optional parameter to Guest Token API V2 to hide selected dashboard metrics for embedded clients. ```json theme={"dark"} { "clientId": "client-123", "dataAppName": "Customer Portal", "params": { "hideDashboardMetrics": [ { "dashboardId": "sales-dashboard", "metricIds": ["revenue-by-region", "gross-margin"] } ] } } ``` ### Fixes: 1. We have added retry handling for Hasura query and layout insert calls to improve reliability. 2. We have fixed the frontend behavior during active Drill-Down V2 saved dashboard reload/render. `datasetMetricCreation` is now skipped when `sqlQuery` already owns the chart rendering, preventing the temporary SQL error flicker. Regards, **The DataBrain Team** **Cloud Updates:** August 17th, 2026 **DataBrain Updates: Features, Enhancements, Fixes: Release Week 111** 📢 ### Features: 1. **Customize Metric Gallery via API:** We have extended the Update Workspace Dashboards API to support incremental updates to metric galleries on existing dashboards. Specific metrics can now be added or removed without recreating the dashboard or impacting other dashboard settings. ```json theme={"dark"} { "dashboardId": "dashboard_id", "appendMetrics": ["metric_id_1", "metric_id_2"], "removedMetrics": ["metric_id_3"] } ``` `appendMetrics` adds the specified metrics to the existing gallery, while `removedMetrics` removes the selected metrics. ### Enhancements: 1. **Prefix and Suffix Options for Conditional Formatting:** Conditional prefix and suffix options are now supported for all table-type charts. (Image 1) Prefix and suffix options for conditional formatting 2. **Personalized Suggestion in Chat Mode:** Chat Mode suggestions have been improved from static examples to smarter, personalized suggestions. These suggestions can consider history, memory, schema, and examples, with deduplication support to surface the top 6 most relevant suggestions. 3. **Updated Chart Settings Column List:** The chart settings column list now reflects dimension and measure changes accurately. 4. **Trino Schema Cache Refactor:** Improved Trino schema refresh performance by moving large schema syncs to an async cache flow. ### Fixes: 1. **OpenSearch Object Value Display:** Fixed object value pairs showing as `[object Object]` when dragged into charts. Regards, **The DataBrain Team.** **Plugin Version:** 0.16.66 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Mandatory Admin-created Filters with Custom Alias Support:** End users can rename dashboard or metric filters configured by the Admin. 2. **Sort Options in Dashboard and Metric Filters:** End users can use ASC/DESC sort options in dashboard and metric filters configured by the Admin. Admins can enable this using the **Allow Sorting** toggle. (Image 1, 2) End-user sort options in dashboard and metric filters Allow Sorting option for admin-created filters 3. **Metric Filters for End Users:** End users can now add metric filters. The below guest token request body enables end-user metric filter creation: ```json theme={"dark"} { "params": { "accessPermissions": { "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "schemaName.tableName", "columns": ["columnName", "columnName"] } ] } } } ``` The `metricFilterColumns` setting ensures end users can create filters only on admin approved columns. ### Enhancements: 1. **Single Value Card Underlying Data Enhancement:** Added a toggle in the UI Theming page to show complete underlying data in fullscreen mode. (Image 3) Single Value Card fullscreen underlying-data and pagination settings 2. **Drill Down Enhancements:** Drill Down now retains chart settings such as renamed column aliases, measure aggregations, filters, sort order, joins, group by, calculated fields, and LIMIT clauses. 3. **Pagination Enhancement in Full Screen Mode:** Added the ability to control pagination for underlying data in full screen mode. (Image 3) Pagination controls for underlying data in fullscreen mode 4. **Pivot Table Enhancements:** Added UI Styling section for Pivot Table Chart V1 and V2. 5. **Number Formatting Enhancement:** Increased the maximum supported limit for digits before the decimal point using custom SQL query. 6. **Dashboard Scroll Minimap Prop:** The dashboard scroll minimap is now disabled by default. It can be enabled using the prop: `enableDashboardMinimap: true` ### Fixes: 1. **Enhanced Mobile View:** Improved filter indication for applied and saved filters, and added a clear filter option for date filters. 2. **Bar Chart Underlying Data:** Resolved an issue where underlying data showed "No data found" when group by was enabled in bar charts. 3. **Trino Compatibility:** Implemented support for MEDIAN or PERCENTILE\_CONT functions compatible with Trino syntax in the DataBrain UI. 4. **Datamart Update API:** Resolved an issue where the update API failed due to invalid GraphQL while syncing the linked access tableList JSONB field. 5. **MSSQL/Fabric Query Fix:** Fixed an issue where SELECT DISTINCT metric queries failed because of a synthetic pagination ORDER BY clause. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Default Aggregation for End Users:**\ Admins can now configure a default aggregation for measures at the Datamart level. The configured aggregation is applied automatically when end users add those measures. 2. **Default Sorting for End Users:**\ Admins can now configure default metric sorting, allowing end users to view metrics sorted by measure in ascending or descending order. Default aggregation and sorting settings for end users ### Enhancements: 1. **Conditional Formatting Improvements:**\ Improved the conditional formatting workflow for Table Charts and Pivot Table Chart V3, making it easier to apply formatting rules to table columns. Conditional formatting improvements for table columns 2. **Log Scale Support for Horizontal Bar Charts:**\ Added a **Log Scale (Base 10)** toggle for Horizontal Bar Charts, similar to the existing Vertical Bar Chart option. Log Scale Base 10 option for Horizontal Bar Charts ### Fixes: 1. **Custom Dataset CTE Queries:**\ Resolved an issue where creating a custom query using a CTE and publishing it as a Custom Dataset could result in an error. 2. **Achieved Metrics Without a Client:**\ Resolved intermittent issues observed when achieved metrics were calculated without a client. **DataBrain Updates: Features, Enhancements, Fixes** ### Enhancements: 1. **MCP Server (`@databrainhq/mcp-server` v0.2.17) — Workspace Metric Upsert:**\ `create_workspace_metric` is now create-or-update. Pass an existing `metricId` to update a workspace metric in place; Dimensions and Measures are re-hydrated from the new SQL so the metric editor stays populated. Publish/archived/draft state is preserved on update. Omit `metricId` to create. 2. **MCP Prompt — `sql-to-workspace-metric`:**\ Added a guided prompt for internal (non-embed) SQL → workspace metric create/update, with dry-run by default and `confirm: "APPLY_TO_PRODUCTION"` before apply. Use `sql-to-metric-migration` when the metric should land on a customer dashboard instead. See the updated tools, prompts, and workspace-metric workflow **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Dashboard Scroll Minimap:**\ Dense dashboards now show a compact overview of all metrics, your current position, and your progress through the dashboard. Click a metric in the minimap to jump directly to it, including metrics that have not rendered yet. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Dashboard Filters in Scheduled Reports:**\ Added support for selecting dashboard filters and their values when configuring Scheduled Reports. Dashboard Filters in Scheduled Reports ### Enhancements: 1. **Pivot Table Chart V3 — Hide Measure Columns:**\ Added a toggle to hide selected measure columns from the chart. 2. **Pivot Table V3 Dimension Display Options:**\ Users can now choose whether a dimension is treated as a hierarchical row level or displayed as a regular non-pivot column. Pivot Table V3 Dimension Display Options and Hidden Measure Columns ### Fixes: 1. **ECharts Chart Resolution:**\ Improved the resolution scale of ECharts React charts in the app and plugin to prevent pixelation when zooming. Chart resolution has also been increased for PDF downloads and Scheduled Reports. 2. **Dropdown Text Wrapping:**\ Fixed a CSS issue that caused dropdown text to wrap incorrectly. 3. **Trino Custom Measure SQL:**\ Fixed an issue where a custom measure using `CAST(ROUND(...))` without an aggregate failed because of `GROUP BY (ExtPrice)`. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Microsoft Fabric Data Source:**\ Added support for Microsoft Fabric as a new data source. Microsoft Fabric Data Source 2. **Multi-Dimension Support for End Users:**\ End users can now create metrics using multiple dimensions. **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **GBP Formatting Option:**\ Users can now format numeric values in GBP for supported chart types. GBP Formatting Option 2. **PDF Export Date Formatting:**\ Users can now customize the date format used in exported PDFs. PDF Export Date Formatting 3. **Line Breaks in Table Chart:**\ We have added **Allow Line Breaks** under **Chart Settings > UI Styling > Enable Content Text Wrap**. When enabled, newline characters from raw data are preserved. Line Breaks in Table Chart 4. **Conditional Formatting for Formatted Values:**\ We have added an option to compare conditional formatting rules against either **Raw Data** or **Formatted Data**. The **Formatted Data** option is available only when number formatting is applied to the selected column. Conditional Formatting for Formatted Values 5. **Dashboard Range Filter Enhancement:**\ Dashboard range filters now support cases where only a minimum or maximum value is provided. Dashboard Range Filter Enhancement 6. **Adding Tenancy Column to Datasource Page:**\ Added a **Tenancy** column on the **Datasource** page to display each datasource's tenancy as a badge. Adding Tenancy Column to Datasource Page ### Fixes: 1. **Pivot Table V3 Downloads:**\ Fixed an issue where Pivot Table V3 downloads did not include calculated measures from Pivot Settings. 2. **Athena Dashboard Metric Download:**\ Fixed an issue in the Athena dashboard metric download flow when a row limit was applied. 3. **Datamart Table Selection:**\ Fixed an issue in Datamart table selection where **Select All Tables** selected all datamart tables instead of only the filtered search results. Plugin Version: `0.16.55` **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Tooltip Dotted Data Point Line:**\ We have implemented the ability to manage dotted data point lines in chart settings. Tooltop Dotted Data Point Line 2. **Styling the Tooltip Container:**\ We have added a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** to style the tooltip card, including padding, border radius, background color, and border color. 3. **Hide the Adjust Spacing Feature in Customize Layout:**\ We have included a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** to hide the **Adjust Spacing** feature in the **Customize Layout** section. 4. **Display All Chart Settings:**\ We have added a prop that bypasses the default chart settings and displays **[all possible settings](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference#custom-chart-settings-reference)**, unless otherwise configured through **[custom-chart-settings](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference#custom-chart-settings-reference)**. 5. **Customize Available Chart Types in End User Create Metric:**\ We have added a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** that allows users to customize the available chart types in the **End User Create Metric** feature. 6. **Export As PDF Server Events:**\ We have added server events to monitor the initiation and completion of the **Export As PDF** operation. ### Fixes: 1. **Hide Enabled Columns for Respective Roles in Datamart:**\ Columns can now be hidden for specific roles when the **Hide To** function is enabled. 2. **Update Dashboard API Error Message:**\ The API now returns a proper error message instead of a 500 error for an invalid `workspaceName`. 3. **Pivot V3 Calculated Columns:**\ We have resolved an issue where exponent-type numeric data, such as `1.91618e-11`, was treated as `-`. 4. **Dashboard Workspace API Validation:**\ Passing an invalid filter name to the Dashboard Workspace API now returns an error response instead of a success response. 5. **Dynamic Properties Filtering:**\ We have fixed an issue where Dynamic Properties were not filtering correctly when Dashboard Filters changed. 6. **Board's Metric Filter:**\ We have resolved an issue where a metric filter applied to a board was not removed after deselecting the board. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **[Update Dashboard Filter in Update Dashboard API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-workspace-dashboards):**\ Support has been added for updating dashboard filters via the Create Dashboard Embed API. 2. **Global Search Feature:**\ You can now search for any workspace, dashboard, or metric within your account. Global search for workspace, dashboard, and metric ### Enhancements: 1. **Dashboard Element Font Color in UI Theming Page:**\ Added support for customizing dashboard element font color in the UI theming page. Dashboard Element Font Color in UI Theming Page 2. **Dashboard Component Customization:**\ Introduced props for: * **[Controlling dashboard component padding](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** * **[Customizing top CTA buttons (Settings, Create Metric)](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** ### Fixes: 1. **Scheduling & Formatting** * Added support for scheduling reports in minutes. * Resolved issues with duration-based conditional formatting. 2. **Pivot Table Improvements (V2 & V3)** * Fixed rendering issues with multiple dimensions. * Corrected incorrect (0) values in numerical dimensions. 3. **Dashboard UI & Layout Fixes** * Fixed overlapping axis labels in horizontal bar charts (embed). * Resolved alignment issues in single value cards. * Fixed font size randomly reducing. * Removed left padding in top-level filters. 4. **Dropdown & Data Sync Issues** * Fixed client dropdown not reflecting updated primary key changes. * Resolved missing dropdown options in dashboard view. 5. **SQL Editor:**\ Fixed an issue where comments were removed during execution due to auto-formatting. 6. **Authentication & Data Integrity** * Fixed expired guest token issues in scheduled email reports. * Resolved duplicate column issues in MSSQL metric creation. 7. **Datamart & Metric Consistency:**\ Fixed an issue where deleted datamart columns continued to appear in the network tab, causing custom columns to show connection errors and invalid metrics to expose the fullscreen action. **DataBrain Updates: Features, Enhancements, Fixes** 📢 ### Features: 1. **Alerts:**\ We have introduced a new feature, *Alerts*, which notifies users when there is an error in the data source connection or when a datamart is broken, making the dashboard unviewable. Alerts for data source and datamart issues ### Enhancements: 1. **Color Selection from Colors Tab:**\ Users can now drag and reorder colors directly from the Colors tab. Color Selection from Colors Tab 2. **Context Window Indicator in AI Copilot:**\ Displays token usage per session (input and output). The limit varies by LLM and determines how much conversation can be retained. Once reached, the chat cannot continue. Context Window Indicator in AI Copilot 3. **Delete Datamart API:**\ Added validation and improved error messaging to prevent the deletion of datamarts that are connected to a workspace. ### Fixes: 1. **Pivot Table V3:**\ Fixed an issue where conditional formatting was not rendering when a suffix was applied. 2. **Horizontal Bar Chart:**\ Added support for the Group By functionality. 3. **Elasticsearch:**\ Fixed issues related to schema sync and index handling. Regards,\ **The DataBrain Team.** **Introducing the Databrain MCP Server** We're excited to announce the public release of the **Databrain MCP Server** (`@databrainhq/mcp-server` v0.2.0) — a new way to manage embedded analytics through your AI assistant. ### What is it? The MCP server implements the [Model Context Protocol](https://modelcontextprotocol.io), connecting AI assistants like **Cursor**, **Claude Desktop**, **Claude Code**, and **Windsurf** directly to the Databrain API. Describe what you want in natural language and the assistant handles the rest. ### Key Features: 1. **Embed Setup via Conversation:** Discover data apps, select dashboards, create embeds, and generate framework-specific frontend code — all through your AI assistant. 2. **Natural Language Data Querying:** Ask questions about your data in plain English. The AI converts them to SQL, executes the query, and returns results with chart suggestions. 3. **24 Tools:** Full embed lifecycle management — creation, theming, filters, localization, permissions, guest tokens, and code generation. 4. **10 Guided Prompts:** Pre-built workflows for common tasks like embedding dashboards, multi-tenant setup, branding, and semantic layer management. 5. **Semantic Layer Management:** Populate and maintain table/column descriptions, synonyms, and example questions entirely through MCP tools. 6. **Multi-Tenant Support:** Create per-client embeds with row-level security using `clientId`. ### Getting Started: Set up in 2 minutes — get your service token, add the config to your AI client, and start talking. ```bash theme={"dark"} npx @databrainhq/mcp-server ``` Full setup guide, workflows, tools reference, and troubleshooting **DataBrain Updates: Features, Enhancements, Fixes** 📢 ### Features: 1. **[Multiple Datamart Connection Support](https://docs.usedatabrain.com/guides/workspace/multi-datamart-workspace):**\ Introduced multi-datamart support, allowing users to select and manage multiple datamarts. 2. **[CRUD API Support for Semantic Layer](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/semantic-layer-api):**\ Users can now **[create](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-semantic-layer)**, **[rename and update](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-semantic-layer)**, and **[delete](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-semantic-layer)** the Semantic Layer via APIs. 3. **[Delete Workspace API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-workspace):**\ Introduced a new DELETE endpoint to enable workspace deletion via API. ### Enhancements: 1. **Pivot Table Chart V3 Calculated Fields:**\ Added support for custom calculated measures, allowing users to create and edit calculated columns. Pivot Table Chart V3 calculated fields 2. **Add Conditional Formatting Support to Pivot Table V3:**\ Introduced conditional styling with dynamic badge colors and background styles. Conditional Formatting Support to Pivot Table V3 3. **[Refinement of List Datamart API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-datamarts#user-content-get-only-query--not-raw-booleans):** We have introduced an `expandDetails` option to the Datamart List API, enabling users to control the inclusion of detailed properties in responses. ### Fixes: 1. **Pagination Sync Issue in Table Charts:**\ Fixed an issue where the default row size option was not in sync with the pagination value for server-side pagination-enabled table charts. 2. **Plugin Manage Metrics: Messaging & Settings Access:**\ When all metrics are hidden, an appropriate message will now be displayed. The settings/manage metrics button remains accessible even when all metrics are hidden. 3. **Addition of Server Events in Embed:**\ Added server-side event tracking for key user actions, including metric creation/editing, data exploration (search, table selection, drag-and-drop, aggregation), chart changes, dashboard interactions (filters, manage metrics, layout), and exports/downloads. 4. **Retaining Primary Database Selection in Update Datamart:**\ Ensured that the primary database selection is preserved during the Update Datamart operation. Regards,\ **The DataBrain Team.** **Plugin Version:** 0.16.34 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Chart Appearance and Chart Actions Props for End Users:**\ We have added properties to the `dbn-dashboard` component that set default values for certain chart settings when a user creates a metric. Additionally, we have introduced properties for each of these settings that can lock the values, making them non-configurable for end users. 2. **Wildcard Support for OpenSearch:**\ We have introduced wildcard syntax support for datamart tables, allowing users to specify flexible patterns when creating or updating tables. 3. **Workspace LLM Configuration via API:**\ We have introduced optional LLM integration in workspace creation and update processes, allowing users to specify an LLM by name. 4. **User-Defined Click Action on Charts:**\ We have introduced a `chartClickFunction` prop to enable custom click actions on charts. The **Pass Complete Data to Function** option allows you to pass the entire row data to the function, enabling dynamic customization of the panel content through the prop. User-Defined Click Action on Charts *** **Plugin Version:** 0.16.33 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Create Empty Dashboard Embed API:**\ We have introduced a prop that allows users to pass data from the Export API response when creating an empty dashboard embed. 2. **Export Embedded Dashboard API:**\ We have introduced an endpoint to export embed data, enhancing data retrieval capabilities for users. ### Enhancements: 1. **Description and Details for Embeds:**\ We have added **Description** and **Details** fields for embeds. Embed Description and Details ### Fixes: 1. We have optimized the bundle size of the plugin. **Plugin Version:** 0.16.32 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Cast or Convert Datetime Columns Based on Guest Token Timezone:**\ Introduced timezone application functionality for datamart and end-user metric creation. Users can now toggle timezone adjustments for date-time columns via a new switch component in Datamart. Timezone-based Datetime Handling 2. **CRUD on CockroachDB Datasource with API:**\ Added API support to create, read, update, and delete CockroachDB datasource configurations programmatically. ### Enhancements: 1. **SSH Tunneling Support for Redis:**\ Introduced SSH tunneling support for Redis connections, enhancing configuration options when creating company Redis instances. SSH Tunneling Support for Redis 2. **Dynamic Adjustment of Axis Limits in Charts:**\ Users can now dynamically adjust the lower and upper limits of the vertical axis in all charts with axes. Dynamic Axis Limits in Charts 3. **Chart Actions Enhancement for Table Chart:**\ Added row redirection and column redirection options for table charts. Table Chart Actions Enhancements 4. **Enhancement of Import Dashboard API:**\ Introduced `dashboardId` and `dashboardName` as parameters in the API. 5. **Support for Reflecting Embed Name While Creating an Empty Dashboard Embed:**\ Added an optional `isRenameDashboard` parameter to the dashboard creation functions, allowing users to conditionally rename dashboards during the creation process. ### Fixes: 1. **Export as PDF Download Speed:**\ Improved performance for exporting dashboards as PDF. 2. **Alias Mismatch After Editing Metrics in Imported Dashboards:**\ Resolved an issue where aliases did not match properly when users edited metrics by adding filters or sorting. 3. **Export Dashboard API Error Handling:**\ Enhanced error handling by introducing a specific error message for invalid dashboard IDs or workspace names, improving API response clarity. 4. **Boolean Dashboard Filter in Postgres:**\ Fixed issues with boolean filters in Postgres-backed dashboards. 5. **OpenSearch Connection Issue:**\ Fixed a connection issue affecting OpenSearch. **Plugin Version:** 0.16.31 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API to Whitelist Domains:**\ We have introduced a new API endpoint `whitelist-domains` to manage whitelisted domains associated with a company. 2. **API for SMTP Settings:**\ We have introduced a new API endpoint `smtp-settings` to save and update company SMTP settings, improving email configuration management. ### Enhancements: 1. **Rotate Data App API using Self Auth:**\ Updated the authentication method for Data App API key rotation from the master token to the current API key. 2. **Customization of "Exporting Dashboard" Prompt Position:**\ Added a property in the dashboard component to customize the position of the Exporting Dashboard prompt:\ `exportMsgPosition: "bottom" | "bottom-left" | "bottom-right" | "center" | "top" | "top-left" | "top-right"`. ### Fixes: 1. **Cockroach DB:**\ Resolved SSL certificate verification and date filter issues. 2. **BigQuery:**\ Fixed an issue with underlying data in the time-series chart. 3. **OpenSearch:**\ Fixed a connection issue. 4. **Datamart:**\ Added unique name constraints in app and APIs. 5. **Data App API Keys:**\ Updated to accept `expiryTime` as a string instead of a number. **Plugin Version:** 0.16.30 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **New Data Source - Cockroach DB:**\ Support has been added for Cockroach DB as a new data source. Cockroach DB 2. **Import & Export Dashboard API:**\ API support has been added for exporting and importing dashboards. 3. **Include Metrics in Template Dashboard:**\ Metrics have been included in the template dashboard for the create dashboard embed API. ### Enhancements: 1. **Table Search Position Options:**\ Configurable search positioning has been introduced for table charts and components. Table Search Position 2. **Waterfall Chart:**\ Measures can now be treated as difference values by selecting the "Difference" option in the Waterfall Settings section. Waterfall Chart 3. **Fullscreen Trigger via Title Click in Embed:**\ A new prop, `enable-title-click-fullscreen={true}`, has been added to enable fullscreen mode when clicking the chart title. ### Fixes: 1. **Waterfall Chart:**\ Issues with chart labels have been resolved. 2. **ExpiryTime Type in Guest Token Creation & Rotate Token API:**\ Handling of the `expiryTime` parameter in `guestToken` and `guestTokenV2` functions has been improved to ensure consistent data types. 3. **Invite User & Resend Mail Flow:**\ Issues in the invite user and resend mail flow have been resolved. **DataBrain Updates: API Documentation** ### Enhancements: 1. **Create Dashboard Embed API – Response field documented:**\ The [Create an Empty Dashboard Embed](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-dashboard-embed) API response now documents the `name` field. Successful responses from `POST /api/v2/data-app/dashboard-embeds` include `id`, `error`, and `name` (the embed configuration name, or `dashboardId` when `name` is not provided). Request examples and response examples in the docs have been updated accordingly. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **AI Suggestions for SQL Editor:**\ Connect your LLM to enable AI-powered suggestions for table names, schema names, and column names. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Improved Join Handling in End-User Metric Creation:**\ Updated the join logic to apply joins only between selected tables and disabled column selection from tables that are not directly connected, reducing invalid joins and improving metric accuracy.\ For example, when a One-to-Many relationship is defined between Orders and Shipments, dragging a column from Shipments will surface only the Shipments and Orders tables for selection. (Gif 1) Improved Join Handling 2. **Revert Option to Default Date in Metric and Dashboard Filters:**\ Users can now switch back to the default date in both metric-level and dashboard-level filters. Revert to Default Date - Metric Filter Revert to Default Date - Dashboard Filter ### Enhancements: 1. **Settings Button Enhancement in Embed:**\ Added `settings-icon` prop to the `dbn-dashboard` component. `settings-icon={JSON.stringify({name: 'random',iconSvg: 'svg'})}` 2. **PDF Table Header Wrapping:**\ Enabled text wrapping for table headers when downloading dashboards as PDFs. 3. **UI Styling Support for Pivot Table V3 Chart:**\ Added UI styling options to the Pivot Table V3 chart. Pivot Table V3 Styling 4. **Dynamic Label Positioning for Waterfall Charts:**\ Labels now dynamically adjust their position based on increases or decreases in values. Dynamic Waterfall Labels 5. **Cumulative Start and End Labels for Waterfall Charts:**\ Added support for displaying cumulative start and cumulative end (running total) labels, making it easier to understand how individual increases or decreases impact the overall total. (Image 5) Cumulative Waterfall Labels 6. **Font Size Customization for Tables and Underlying Data:**\ Users can now control font sizes via Chart Settings for UI-styled table charts, and via Theme Settings for table charts and underlying data views (popup and fullscreen), ensuring improved readability and visual consistency. (Images 6, 7) Table Font Size Customization Underlying Data Font Size Customization ### Fixes: 1. **Fullscreen and Download Metric Options in Embed:**\ Fixed an issue where Fullscreen and Download options were not visible in embedded dashboards containing merged metrics. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Sticky Dashboard Filters:** We've added a Sticky option to the Dashboard Filter in the `dbn-component`, allowing dashboard filters to remain fixed while scrolling. Prop: `is-sticky-dashboard-filters = {true}` 2. **Datamart & Semantic Layer Revamp:**\ We're introducing a Datamart revamp to improve scalability and simplify data modeling. **What's changing:** * **Define Relationships section:** Table relationships (Joins) and Cardinality will now be defined in the Datamart. * **Configure Tenancy section:** Tenancy is configured first during Datamart creation to set up the base and Client ID mapping should be defined in Datamart * **Datamart APIs** will support joins and client ID mapping **Benefits:** cleaner models, consistent tenancy, reusable Datamarts, and simpler Semantic Layer setup. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Create Datamart API – Hide Table:** Added support for `tableList.isHide` to hide entire tables from the Datamart interface. Refer to the [Create Datamart API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datamart#:~:text=tableList.isHide,the%20datamart%20interface) documentation for details. 2. **Create Datamart API – Hide Table Column List:** Added support for `tableList.columns.isHide` to hide specific columns from the Datamart interface. Learn more in the [Create Datamart API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datamart#:~:text=tableList.isHide,the%20datamart%20interface) documentation. 3. **CRUD APIs for Datasource:** Introduced full CRUD API support for managing datasources. See the [Datasource API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datasource) documentation. 4. **Pie Chart – Measure Breakdown:** Added measure-based breakdown for Pie Charts, where wedges are generated based on the number of measures. Piechart 5. **Waterfall Chart V2:** Introduced Waterfall Chart V2 with cumulative value support. Waterfall Chart V2 6. **Multiple Scheduled Reports:** Enabled end users to create and manage multiple scheduled reports. 7. **API for Listing User-Created Reports:** Added API support to list user-created scheduled reports by embed. Refer to the [List Schedule Reports API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-schedule-reports-by-embed) documentation. 8. **Embed Renaming API:** Added API support to assign and update embed names. See the [Rename Embed API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/rename-embed) documentation. ### Enhancements: 1. **Dashboard Embed Metadata API:** Added new parameters to fetch additional embed metadata, including `createdAt`, `updatedAt`, `externalMetricId`, `dataAppId`, `embedId`, and `name`. Learn more in the List Embed API documentation. 2. **Whitelist Domain Support:** Added wildcard support and improved Top-Level Domain handling for whitelisted domains. ### Fixes: 1. **Whitelist Domain Validation:** Fixed issues related to incorrect Top-Level Domain handling in whitelisted domains. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Service Tokens + API Key Rotation:** You can now create and manage service tokens directly within the app, enabling secure API key rotation through the Data App for safer long-term usage. Service Tokens 2. **Dashboard Deletion via Embed Config:** Added support for dashboard deletion using the URL parameter: `isDeleteDashboard: true` ### Enhancements: 1. **CSV and XLSX Support in Scheduled Reports:** Users can now schedule reports in CSV and Excel (.xlsx) formats, expanding export flexibility in automated schedules. CSV and XLSX Formats ### Fixes: 1. **Resolved Metric Loading Issue:** Fixed an issue where loading a metric caused the entire dashboard to load instead of just the selected metric. 2. **Dashboard Filters on Empty Dashboards:** Filters now work correctly even when a dashboard contains no visualizations. 3. **Schedule Report in Embed:** Scheduled reports within embedded dashboards now work contextually based on the selected dashboard and client. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Publish Metric API:** Added support to publish all metrics via API using the property `isPublished: true`. 2. **Update Datamart API:** Added support to update datamarts via API. 3. **Workspace APIs:** Added APIs for Create Workspace, Update Workspace, and List Workspaces. ### Enhancements: 1. **Embed Axis Color Properties:** Chart axis colors can now be customized using: ```json theme={"dark"} { "chartAppearance": { "horizontalAxis": { "color": "#cd00e0ff", "axisColor": "#0009b6ff" }, "verticalAxis": { "color": "#b6a700ff", "axisColor": "#b60000ff" } } } ``` ### Fixes: 1. **Filter Dropdown in Metric Creation:** Resolved issues affecting simple filter dropdown values. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Auto Joins in End-User Metric:** You can now set up auto joins in the Semantic layer. End users can drag and drop to create metrics from different tables seamlessly. **DataBrain Updates: Features, Fixes** ### Features: 1. **User Defined Fields (UDF):** Easily customize dashboards with your own data fields — no schema changes needed. DataBrain now auto-detects and supports both common and client-specific fields as dynamic filters and chart axes for flexible, personalized insights. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Gemini LLM**: Added a new connector for LLMs — Gemini. Gemini LLM ### Enhancements: 1. **Filter Elements for Fetch Metrics API**: Added a new parameter `isMetric=true` to the Fetch Metrics API. 2. **Prop for Download Dashboard as PDF**: Introduced a new embed prop `enable-download-all-pdf={true}` to enable dashboard PDF downloads. 3. **Naming Conventions & Methods in End User APIs**: Updated HTTP methods to `POST`, `GET`, `PUT`, and `DELETE` for improved consistency. ### Fixes: 1. **Trino**: Resolved a server error when creating a metric caused by “Zero-length delimited identifier not allowed.” 2. **Logs in Playground**: Implemented a logging mechanism in the playground environment for better traceability. 3. **Chat Mode**: Fixed query-related and limit issues in chat mode. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API Endpoint for End User Dashboard Creation**: End users can now create dashboards directly through the API. 2. **New Data Source – Trino**: Added support for a new data source — Trino. Trino Data Source 3. **Single-Click Download for Metrics Data in Embed**: End users can now download the underlying data for all metrics with one click by adding the prop:\ `enable-download-csv="true"` 4. **Fullscreen Metrics in Embed**: Metrics can now fit fullscreen in embeds using the prop:\ `shouldFitFullScreen="true"` ### Enhancements: 1. **Support for Label and Hide Options in Datamart & Create Metric**: You can now add labels to columns and hide columns on the create metric page by configuring them in the Datamart layer. Label and Hide Options 2. **Variable Value Support for Next Preset Date Filter**: Added variable value support for the “Next” preset date option in metric and dashboard filters. Variable Support in Metric Filter Variable Support in Dashboard Filter ### Fixes: 1. **Removed Background Color from Dashboard PDFs**: Dashboard PDF exports no longer include unwanted background colors. \*\*DataBrain Updates: Features, Enhancements, Fixes \*\* ### Features: 1. **Single Click Download for Metrics Data**: Users can now download the underlying data for all metrics with just one click. Download Metrics ### Enhancements: 1. **Customizable Fonts for Table Chart**: Added options to configure font family, font color, and font weight in table charts. Font options for table chart 2. **UI Theming for Underlying Data**: Introduced settings to customize header text, background color, content text, spacing, and font weight for underlying data. UI theming options for Underlying Data ### Fixes: 1. **UI Theming Fixes**: Resolved inconsistencies in theme fonts, labels, and background styling in Single Select, Preset Date, and Range dropdowns. 2. **Metric Filter in Dashboard View**: Fixed issues affecting the proper functioning of metric filters in dashboard views. 3. **Datasource Logo in Dropdowns**: Datasource logos are now displayed alongside datasource names in dropdown menus. 4. **Auto Filter Reset Defaults**: Corrected issues where default values in Single Select and Multi Select auto filters were not resetting properly. **Plugin Version:** 0.16.5 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Boards**: Users can now create multiple views of a dashboard based on applied dashboard filters and easily switch between them. ### Enhancements: 1. **Set Default Client Per Dashboard**: Users can set a default client for each dashboard. 2. **Edit Metric**: Users can edit a metric by clicking the edit icon next to the metric name. 3. **Lifetime Option in Single Value Card**: A new option, *Lifetime*, has been added to Single Value Cards to perform aggregate calculations without comparisons. 4. **Customize Dashboard Layout in UI Theming**: Users can now configure vertical and horizontal gaps for dashboard layouts in the UI Theming page. 5. **Height-Based Auto Pagination in Table Charts**: Table charts now support automatic pagination based on height, adjusting the number of rows dynamically. 6. **Prop for Breadcrumb (Drill Down) Color and Font Family**: Users can now add color and font family to breadcrumbs when drill down is enabled in embed. 7. **Prop to Change Badge Color of Multi-Select Filter**: Introduced a property for pill color in the multi-select badges in embed. ### Fixes: 1. **Updated Results Table for No Data**: The image displayed when a query returns no results in the Query Builder has been updated. 2. **Drill-Down Issue with Unselected Dimensions**: Fixed an issue where an unselected dimension appeared in the drill-down hierarchy. 3. **Date Filter Font Consistency**: Fixed font inconsistencies in date-based metric filters. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Rules Builder**: Users can now hide or unhide metrics based on selected charts. ### Enhancements: 1. **Download Properties & Full-Screen Mode in Embed Options**: Added the ability to download data without applying filters to the underlying data and introduced a full-screen option for an improved user experience. 2. **Separate Alignment for Table Chart Columns**: Users can now align table chart columns individually as Left, Center, or Right. 3. **'Next' Support in Dashboard & Metric Date Filters**: Users can now preset future date ranges using the *Next* option. 4. **Multi-Database Support**: Added support for multiple databases when configuring data sources. *** ### Fixes: 1. **Metric Filter Apostrophe Issue**: Resolved an issue where multi-select filters with values containing an apostrophe (`'`) were not working correctly. 2. **Redshift Column Aliases**: Fixed an issue where column aliases containing `#` caused errors. 3. **Dashboard Filter Defaults**: Fixed an issue with the Auto and Manual options in the default value setting of dashboard filters. **DataBrain Updates: Enhancements, Fixes** :loudspeaker: ### Enhancements: 1. **'percentile\_cont' and 'percentile\_disc' Functions for Measures**: You can now calculate continuous and discrete percentiles using these new functions. 2. **Download Dashboard as PDF**: Users can now download dashboards in PDF format. 3. **Dropdown Multi-select Filter for String Columns in Table Chart**: A dropdown multi-select filter can now be added to any string column in a table chart. 4. **Trendline Support**: We have introduced trendline functionality in table charts using custom SQL. *** ### Fixes: 1. **Default option for LLMs**: You can now set any LLM as the default option. 2. **Metric Filter Styling Issue**: Fixed font and font size inconsistencies in date-type metric filters. 3. **Underlying Data Download in OpenSearch**: Resolved issues related to downloading underlying data in OpenSearch. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API Endpoint for Datamart**: Users can now perform CRUD operations on datamarts using the API endpoint. 2. **Hybrid (Stacked + Bar) Chart**: A new chart type, *Hybrid Bar*, has been introduced. *** ### Enhancements: 1. **Metric Filter Interaction**: Improved workflow for switching between 'Apply On' and 'Filter Options' in Metric Filters for smoother navigation. 2. **Gantt Chart Styling**: Added bar styling options for Gantt Chart, including Bar Height, Top Radius, and Bottom Radius. *** ### Fixes: 1. **Hide App Filter in Filter Box**: The App Filter is now hidden in the dashboard filter box to enhance security and ensure proper functionality. 2. **Elastic Search**: Fixed an issue that occurred when creating custom datasets. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Gantt Chart**: Introducing the Gantt Chart for enhanced timeline-based visualization of tasks and projects. 2. **Y Axis - Log Scale**: Added the ability to convert the Y-axis to a logarithmic scale for improved visualization of wide-ranging values. 3. **New Data Source - OpenSearch**: Now supporting OpenSearch as a data source, expanding your integration options. 4. **Optional Variable Filters**: Variable filters can now be made optional using square brackets in code blocks for greater flexibility. 5. **Click Action on Single Value Card**: Enable interactive experiences by configuring click actions on Single Value Cards. *** ### Enhancements: 1. **Multi-Select Y-Axis**: You can now enable multi-selection for the Y-axis in bar, line, and area charts. 2. **Underlying Data Download**: Added support to download filtered underlying data for deeper offline analysis. 3. **Badge Color in Table Chart**: Introduced the ability to set badge colors in table chart conditional formatting. 4. **Default Dynamic Dates in Filters**: Set default values like Today, Tomorrow, and Yesterday in single-date filters. 5. **Multi-Column Click Actions in Table Charts**: Configure click actions for multiple columns in table charts. *** ### Fixes: 1. **Switch Select Default Value**: Resolved inconsistencies in Switch Select options by setting a default value. 2. **Dynamic Properties in Descriptive Elements**: Fixed loading issues in dynamic properties across footnote, title, description, and long description. 3. **Athena Load Time Disparity**: Addressed inconsistencies in load time between Query Editor and Chart Builder for Athena data source. 4. **Dashboard Filter**: Ad the ability to clear default values in dashboard filters. 5. **Scheduled Reports**: Fixed formatting issues in PDF exports for scheduled reports. **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Drill Down Revamp**: We've updated the UI of Drill Down Feature to ensure better clarity and visibility. 2. **Custom SQL Revamp**: We've enhanced the Custom SQL interface to offer a cleaner editing experience and improved validation feedback for better query building. Users can write custom SQL queries and save them as Table Chart, Table Chart with Dynamic Table, New Chart or Custom Dataset. 3. **Single Value Card**: We've added alignment and font options, along with dynamic property support for sub-header text in the Single Value Card. String-based conditional formatting support has also been introduced. 4. **Metric Border Color**: Users can now specify the metric border color globally from the UI Theming page. ### Fixes: 1. **Filter Disappearance on Sync in Metric Page**: Resolved an issue with the variable metric filter for the Redshift data source. 2. **Custom Columns in Simple Filter**: Fixed an issue where custom columns were not appearing in the simple filter. **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Syntax Validation for Calculated Fields**: We've added an icon to validate the syntax of SQL queries when creating calculated fields. 2. **Background Color Option for Metric Summary**: You can now set a background color for the metric summary card. 3. **Letter Spacing, Line Height in Metric Summary Prompt**: You can now specify letter spacing (in px) and line height in the metric summary prompt. 4. **Delete Option for Custom Roles**: A delete option is now available for custom roles. 5. **Chart settings for chart title, axis labels, axis values, and legend** have been added globally under the 'UI Theming' section on the Embed Settings page. ### Fixes: 1. **Switch Y Axis Enablement with Individual Number Formatting**: When the "Switch Y-Axis" option is enabled, each measure now correctly applies its own number formatting settings. **DataBrain Updates: Enhancements** ### Enhancements: 1. **Auto-suggest Joins on Create Metric with AI**: You can now automatically join data using AI suggestions. 2. **Auto-Select All in Multi-Select Filters**: We've added a toggle to automatically select all values in metric and dashboard filters by default. 3. **Variable Support in Custom Query of Metric Filter**: You can now pass the variable value from one metric filter into the custom query of another — for example, using the “Product Category” filter value in the “Product Name” filter. 4. **New Number Formatting Options**: We've introduced new number formatting options like “Thousands,” “Millions,” and “Billions”. **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Date Restriction Feature in Preset Date Dashboard Filters**: We have added an "Enable Restrictions" toggle to the Preset Date Dashboard filter, similar to the Metric Filter. 2. **OIDC Identity Provider (IDP) Support**: Users can now create an OIDC-based IDP for Single Sign-On (SSO) under MFA & SSO Settings ### Fixes: 1. **Dashboard UI Fix**: Resolved an issue where the 'Reset' button overlapped with other UI elements on the dashboard page. 2. **Report Scheduling**: Added user prompts for improved clarity and guidance during report scheduling. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **New Data Source – Athena**: We've added support for a new data source: Athena. 2. **Horizontal Combo Chart**: A new chart type has been introduced, similar to the combo multi-scale chart but arranged horizontally. 3. **Bubble Chart V2**: The updated version of the Bubble Chart now allows users to specify bubble size. You can now set a measure for bubble size and drag & drop measures into dimensions. ### Enhancements: 1. **Date Range Mapping for Single Value Card Comparison**: Single value cards now automatically reflect the selected dashboard date filter range. If "Lifetime" is chosen, the card uses the comparison value set in its settings. 2. **Grid Dividers in Merge Metric**: Users can now add grid dividers between different metrics and enhance them with background colors. ### Fixes: 1. Resolved an issue with the preset date dashboard filter in Firebolt. **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Add Alignment Option for Single-Value Card**: You can now align the value in Single-Value Cards.\ Navigate to Settings > Appearance > Customizations > Alignment for more control over layout. ### Enhancements: 1. **Table Chart Minimum Height**: Reduced the minimum height of Table Charts in dashboards for better space utilization and layout flexibility. ### Fixes: 1. **Download Array Datatype Column Values**: Fixed an issue where array-type column values were not downloaded correctly. 2. **Single Value Card Resizing**: Resolved inconsistencies in resizing behavior for Single-Value Cards. 3. **Progress V2 Number Formatting**: Addressed incorrect number formatting on upper limit when using dynamic properties. 4. **Combo Chart Duplicate Axis**: Fixed an issue where duplicate axes appeared in Combo Charts. **DataBrain Update: Enhancements** ### Enhancements 1. **Complex Sort in Metrics**: Added a feature to generate SQL for custom sorting beyond the default lexicographical ASC and DESC provided by SQL. 2. **Role Permissions for Metric Elements**: Introduced an option to manage role-based permissions for metric elements. 3. **"All Clients" Option**: Added an "All Clients" selection on the metric creation page. 4. **Transpose Data in Table Charts**: Introduced a toggle to switch rows and columns in table charts. **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Metric Expression Support in Elements**: We have introduced metric expression support in elements, allowing users to compute values using metric ID. 2. **Added Variable Filter for Preset Date Filter**: Implemented a variable filter in the preset date option for dashboards. ### Fixes 1. **Improved Pagination on the Explore Data Page**: Fixed an issue where pagination did not display correctly, ensuring a smoother navigation experience. 2. **UI Update**: Resolved an issue with tooltips for better usability. **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Font Style Options in Axis Charts**: Added Font Family, Font Size, and Font Weight options for horizontal and vertical axis names 2. **Font Styling for Metric AI Summary**: Users can now customize font styles in the Metric AI Summary 3. **Text Wrap in Combo Multi-Scales Chart**: Users can now define a value to break text in the Y-axis name of the combo multi-scales chart 4. **Customize Date Format**: Users can now set their preferred date format for the date filter in the "UI Theming" page ### Fixes 1. **Explore Data**: Fixed a download issue in the Explore Data feature **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Sorting and Number Formatting for Pivot Table V2**: Added options for sorting and number formatting in Pivot Table V2 2. **Custom Value Redirection in Table Chart**: Users can now click on a specific value in the Table Chart to be redirected to a designated link ### Fixes 1. **UI Update**: Chart Tooltip settings will remain hidden until the "Label Tooltip" toggle is enabled 2. **Metric Alignment Fix**: Resolved an issue where metric alignment changed after exporting and importing a dashboard. **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Editability of Created Views in Custom Datasets**: Exploring the feasibility of enabling editing and deleting capabilities for previously created views within custom datasets. 2. **Enhanced Pivot Table V3** 3. **Improved UI for Table Chart Pagination** 4. **Metric Background Color in Single Value Card**: Users can now add a background color to Single Value Cards. 5. **Set Config**: User can now set Data Config Options in Embedded Dashboards. ### Fixes 1. **Fixed flickering issue in bar charts.** 2. **BigQuery Data Source Fixes**: Resolved issues with `GROUP BY`, single quotes in filters, and AI-powered query formatting. **DataBrain Update: Features, Enhancements & Fixes** ### Feature: 1. **Datasource Sync API**: Exposed an API for syncing the datasource ### Enhancements: 1. **Dashboard Date Filter & Time-Series Chart Integration**: We have added support for mapping dashboard date filter options with time-series charts for improved synchronization 2. **Bar Styling for Combo Multi-Scales Chart**: Added a "Bar Styling" option to the combo multi-scales chart for better customization. This feature allows users to fine-tune the appearance of bars for improved visualization and readability with key Customization Options: * Bar Width – Adjust the width of bars to control spacing and visual clarity * Bar Top Radius – Round the top edges of bars for a softer, modern look * Bar Bottom Radius – Customize the bottom edge roundness for a polished appearance ### Fixes: 1. **Bubble Chart in Firebolt**: Resolved an issue affecting the Bubble chart when using the Firebolt datasource 2. **UI Update (Fullscreen Dropdown Component)**: Fixed an inconsistency in dropdown behavior when in fullscreen mode ### DataBrain Update: Enhancements & Fixes #### Enhancements 1. **Horizontal Chart:** Added Switch X-Axis and Switch Y-Axis features for improved flexibility 2. **Sankey Chart:** Introduced Switch Measure functionality for better customization #### Fixes 1. Resolved an issue where the Switch X-Axis Dropdowns displayed removed dimension values 2. Fixed duplicate values appearing in the Filter Panel dropdown in Custom Query Mode **DataBrain Updates: Features, Enhancements, Fixes**: ### Features: 1. **Rearrange Metric Filters**: You can now rearrange metric filters on the update/create metric page using drag-and-drop, making customization easier and more intuitive. 2. **Save a Custom Dataset (View) to Multi-Selected Datasource**: You can now save a custom dataset across multiple selected data sources, enabling seamless data management and greater flexibility. Refer to the document below: 3. **Support Fiscal Year in Date Filter**: You can now set up a custom fiscal year filter in DataBrain to filter data based on the Indian Financial Year. Refer to the documentation below: 4. **Easier Access to Frequently Used Tables**: Frequently used tables now appear at the top of the schema sidebar on the metric creation page, improving accessibility and efficiency. ### Enhancements: 1. **Adaptive formatting for Indian decimals**: The Indian Number System now considers values up to two decimal places. 2. **Enhanced Chart Controls for End Users**: End users can now access additional chart options, including Enable Cumulative Behavior, Dynamic Behavior, and Chart Zoom, for improved data visualization and interaction. ### Fixes: 1. **UI update**: We have enhanced the user experience by eliminating flickering when switching between the Charts Panel and Settings Panel, ensuring a smoother and more seamless transition. 2. **Improved Reset Password Flow**: Expired Reset Password links now immediately display a “Reset Password Link Expired” message, preventing unnecessary input. 3. **Date filter**: The Date Filter now accepts only four-digit years, preventing incorrect inputs. **DataBrain Updates: Features, Enhancements, Fixes:** **Features:** 1. **Archive Metrics**: End users can now archive metrics for better organization. **Enhancements:** 1. **Copy Generated SQL with One Click**: A new "Copy" button allows you to easily copy the generated SQL query. 2. **Customizable Color Palettes**: Modify colors in existing palettes anytime to match your theme by clicking on the edit icon. 3. **Improved Dashboard and Metric Filters**: Added a "Clear All" option for Dashboard/Metric filters. 4. **Enhanced Table Charts**: Introduced an input field to customize view text in table charts. **Fixes:** 1. **Drill Query Filtering**: Resolved an issue that previously prevented proper handling of number-type columns in drill query filters. **Features, Enhancements, Fixes:** ### Features: 1. **Drill Down for Tree Map:** Introducing drill-down functionality in Tree Map charts! Click on a section to explore deeper levels of data effortlessly. 2. **Add RHS Custom SQL Support:** Added the ability to control how selected options from a dashboard dropdown are applied on the RHS of the `WHERE` clause. Use the `{{global_selected_values}}` variable to modify selected values dynamically (e.g., applying transformations like `CONCAT`). 3. **Chart Click Action with Metric:** Now, clicking on a metric within a chart allows seamless navigation to another related metric for enhanced data exploration. 4. **Add View Button in Table Chart:** Added a "View" button in table charts, enabling users to expand selected columns within a row for better data visibility. ### Enhancements: 1. **Adaptive Formatting – Indian Number System:** Added support for number formatting in the Indian system (e.g., lakh, crore) for improved readability. ### Features, Enhancements, Fixes: #### Features: 1. **Footnote as a Rich Text Box:** Footnotes are now powered by a React text box, allowing you to add links, change colors, and apply formatting like bold and italics for better customization. 2. **Hide Dashboard Filter in Embed Code:** You can now control the visibility of dashboard filters in embedded dashboards. This is useful for cases where different user groups need different filter options. For example, US customers can see the US fiscal year, while Indian customers see the Indian fiscal year—without displaying unnecessary filters. Please refer the below link: 3. **Cumulative Option for Line and Area Charts:** A new "Cumulative" option has been added to Line and Area charts, accessible under Chart Settings > Appearance > Features > Cumulative for better trend analysis. #### Enhancements: 1. **Open Dashboards & Metrics in a New Tab:** You can now right-click on a dashboard or metric from the homepage to open it in a new tab for easier navigation. 2. **UI Theming Update:** You now have the option to remove the stroke around metric cards for a cleaner visual experience. **Features, Enhancements, Fixes:** ### Features: 1. **New Geo Region Map**: We’ve expanded our list of available geographic visualizations by adding an Indian states map, expanding our visualizing abilities. 2. **Preview Link Management**: Track all preview links generated for dashboards and delete those no longer needed for improved link management. ### Enhancements: 1. **Dynamic Property Support**: Added support for dynamic property implementation in the lower and upper limit setup. 2. **Clear All Option**: Easily clear all columns added in measures or dimensions with a single click using the "Clear All" functionality. ### Fixes: 1. **Date Restriction in Metric Filter**: Resolved an issue with date restrictions in the metric filter for accurate filtering. 2. **Time Series for MSSQL**: Fixed time series functionality for MSSQL to ensure proper data representation. ### Features, Enhancements, Fixes #### **Features** 1. **New Progress Bar Chart**\ Introducing a progress bar chart with conditional formatting! It effectively handles cases where values exceed limits for accurate data representation. 3MB 2. **Merge Layouts**\ Easily merge multiple metrics and rearrange them with the same flexibility as the dashboard's custom layout. 6MB 3. **New Data Sources – Firebolt and SingleStore**\ Added support for Firebolt and SingleStore for enhanced data connectivity. *** #### **Enhancements** 1. **Revamped Chart Panel in Create Metric Page**\ Charts are now grouped under categories, making it easier to find and search for the desired visualizations. 2MB # Self hosted changelog Source: https://docs.usedatabrain.com/changelog/self-hosted-changelog **Self - Hosted Updates:** August 12th, 2026
**Image Version:** 1.2.32
**Plugin Version:** 0.16.65 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Default Aggregation for Users:** Admins can now configure a default aggregation for measures at the Datamart level, and the aggregate will be added by default for measures for end users. (Image 1) 2. **Default Sorting for Users:** Admins can now configure default metric sorting, allowing end users to view metrics sorted by measure in ascending or descending order. (Image 1) Default aggregation and sorting settings for end users 3. **Mandatory Admin-created Filters with Custom Alias Support:** End users can rename dashboard or metric filters configured by the Admin. 4. **Sort Options in Dashboard and Metric Filters:** End users can use ASC/DESC sort options in dashboard and metric filters configured by the Admin. Admins can enable this using the **Allow Sorting** toggle. (Image 2, 3) End-user sort options in dashboard and metric filters Allow Sorting option for admin-created filters 5. **Metric Filters for End Users:** End users can now add metric filters. The below guest token request body enables end-user metric filter creation: ```json theme={"dark"} { "params": { "accessPermissions": { "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "schemaName.tableName", "columns": ["columnName", "columnName"] } ] } } } ``` The `metricFilterColumns` setting ensures end users can create filters only on admin approved columns. ### Enhancements: 1. **Single Value Card Underlying Data Enhancement:** Added a toggle in the UI Theming page to show complete underlying data in fullscreen mode. (Image 4) Single Value Card fullscreen underlying-data and pagination settings 2. **Drill Down Enhancements:** Drill Down now retains chart settings such as renamed column aliases, measure aggregations, filters, sort order, joins, group by, calculated fields, and LIMIT clauses. 3. **Pagination Enhancement in Full Screen Mode:** Added the ability to control pagination for underlying data in full screen mode. (Image 4) Pagination controls for underlying data in fullscreen mode 4. **Conditional Formatting Improvements:** Improved the conditional formatting workflow for table charts and Pivot Table Chart V3, making it easier to apply formatting rules to table columns. (Image 5) Conditional formatting improvements for table columns 5. **Log Scale Support for Horizontal Bar Charts:** Added a **Log Scale (Base 10)** toggle for horizontal bar charts, similar to the existing vertical bar chart option. (Image 6) Log Scale Base 10 option for Horizontal Bar Charts 6. **Pivot Table Enhancements:** Added UI Styling section for Pivot Table Chart V1 and V2. 7. **Number Formatting Enhancement:** Increased the maximum supported limit for digits before the decimal point using custom SQL query. 8. **Dashboard Scroll Minimap Prop:** The dashboard scroll minimap is now disabled by default. It can be enabled using the prop: `enableDashboardMinimap: true` ### Fixes: 1. **Enhanced Mobile View:** Improved filter indication for applied and saved filters, and added a clear filter option for date filters. 2. **Bar Chart Underlying Data:** Resolved an issue where underlying data showed "No data found" when group by was enabled in bar charts. 3. **Trino Compatibility:** Implemented support for MEDIAN or PERCENTILE\_CONT functions compatible with Trino syntax in the DataBrain UI. 4. **Datamart Update API:** Resolved an issue where the update API failed due to invalid GraphQL while syncing the linked access tableList JSONB field. 5. **MSSQL/Fabric Query Fix:** Fixed an issue where SELECT DISTINCT metric queries failed because of a synthetic pagination ORDER BY clause.
**Image Version:** 1.2.31\ **Plugin Version:** 0.16.61 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Dashboard Filters in Scheduled Reports:**\ Added support for selecting dashboard filters and their values when configuring Scheduled Reports. Dashboard Filters in Scheduled Reports ### Enhancements: 1. **Pivot Table V3 Enhancements:**\ Added support for hiding measure columns, choosing whether dimensions appear as hierarchical row levels or regular columns, renaming and reordering custom calculated measures, and displaying comma-separated distinct values at higher hierarchical levels. Pivot Table V3 dimension and measure display options 2. **Dashboard Scroll Minimap:**\ Dense dashboards now show a compact overview of all metrics, your current position, and your progress through the dashboard. Click a metric in the minimap to jump directly to it, including metrics that have not rendered yet. **Image Version:** 1.2.28\ **Plugin Version:** 0.16.56 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Microsoft Fabric Data Source:**\ Added support for Microsoft Fabric as a new data source. Microsoft Fabric Data Source 2. **Multi-Dimension Support for End Users:**\ End users can now create metrics using multiple dimensions. **Image Version:** 1.2.25\ **Plugin Version:** 0.16.55 **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **GBP Formatting Option:**\ Users can now format numeric values in GBP for supported chart types. GBP Formatting Option 2. **PDF Export Date Formatting:**\ Users can now customize the date format used in exported PDFs. PDF Export Date Formatting 3. **Line Breaks in Table Chart:**\ We have added **Allow Line Breaks** under **Chart Settings > UI Styling > Enable Content Text Wrap**. When enabled, newline characters from raw data are preserved. Line Breaks in Table Chart 4. **Conditional Formatting for Formatted Values:**\ We have added an option to compare conditional formatting rules against either **Raw Data** or **Formatted Data**. The **Formatted Data** option is available only when number formatting is applied to the selected column. Conditional Formatting for Formatted Values 5. **Dashboard Range Filter Enhancement:**\ Dashboard range filters now support cases where only a minimum or maximum value is provided. Dashboard Range Filter Enhancement 6. **Adding Tenancy Column to Datasource Page:**\ Added a **Tenancy** column on the **Datasource** page to display each datasource's tenancy as a badge. Adding Tenancy Column to Datasource Page ### Fixes: 1. **Pivot Table V3 Downloads:**\ Fixed an issue where Pivot Table V3 downloads did not include calculated measures from Pivot Settings. 2. **Athena Dashboard Metric Download:**\ Fixed an issue in the Athena dashboard metric download flow when a row limit was applied. 3. **Datamart Table Selection:**\ Fixed an issue in Datamart table selection where **Select All Tables** selected all datamart tables instead of only the filtered search results. Regards,\ **The DataBrain Team.** **Image Version:** 1.2.24\ **Plugin Version:** 0.16.51 **DataBrain Updates: Enhancements, Fixes** 📢 ### Enhancements: 1. **Tooltip Dotted Data Point Line:**\ We have implemented the ability to manage dotted data point lines in chart settings. Tooltop Dotted Data Point Line 2. **Styling the Tooltip Container:**\ We have added a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** to style the tooltip card, including padding, border radius, background color, and border color. 3. **Hide the Adjust Spacing Feature in Customize Layout:**\ We have included a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** to hide the **Adjust Spacing** feature in the **Customize Layout** section. 4. **Display All Chart Settings:**\ We have added a prop that bypasses the default chart settings and displays **[all possible settings](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference#custom-chart-settings-reference)**, unless otherwise configured through **[custom-chart-settings](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference#custom-chart-settings-reference)**. 5. **Customize Available Chart Types in End User Create Metric:**\ We have added a **[prop](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** that allows users to customize the available chart types in the **End User Create Metric** feature. 6. **Export As PDF Server Events:**\ We have added server events to monitor the initiation and completion of the **Export As PDF** operation. 7. **Client Dropdown Visibility for Editor Users:**\ Added a **View Clients** permission under the Dashboard section in Roles. This permission controls the visibility of the client dropdown in multi-tenancy scenarios on Dashboard and Create Metric pages. 8. **Hide Enabled Columns for Respective Roles in Datamart:**\ Columns can now be hidden for specific roles when the **Hide To** function is enabled. ### Fixes: 1. **Update Dashboard API Error Message:**\ The API now returns a proper error message instead of a 500 error for an invalid `workspaceName`. 2. **Pivot V3 Calculated Columns:**\ We have resolved an issue where exponent-type numeric data, such as `1.91618e-11`, was treated as `-`. 3. **Range Filter:**\ Fixed an issue where underlying data was not filtered correctly when a range filter was applied. Regards,\ **The DataBrain Team.** **Image Version:** 1.2.18\ **Plugin Version:** 0.16.43 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **[Update Dashboard Filter in Update Dashboard API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-workspace-dashboards):**\ Support has been added for updating dashboard filters via the `Create Dashboard Embed API`. 2. **Global Search Feature:**\ Users can now search for any workspace, dashboard, or metric within their account. Global search for workspace, dashboard, and metric ### Enhancements: 1. **Dashboard Element Font Color in UI Theming Page:**\ Added support for customizing dashboard element font colors within the UI theming page. Dashboard Element Font Color in UI Theming Page 2. **Dashboard Component Customization:**\ Introduced new props for: * **[Controlling dashboard component padding](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** * **[Customizing top CTA buttons (Settings, Create Metric)](https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference)** ### Fixes: 1. **Scheduling & Formatting** * Added support for scheduling reports in minutes. * Resolved issues with duration-based conditional formatting. 2. **Pivot Table Improvements (V2 & V3)** * Fixed rendering issues when using multiple dimensions. * Corrected incorrect (0) values appearing in numerical dimensions. 3. **Dashboard UI & Layout Fixes** * Fixed overlapping axis labels in horizontal bar charts (specifically for embeds). * Resolved alignment issues in single value cards. * Fixed an issue where font sizes would randomly reduce. * Removed left padding in top-level filters. 4. **Dropdown & Data Sync Issues** * Fixed the client dropdown not reflecting updated primary key changes. * Resolved missing dropdown options in the dashboard view. 5. **SQL Editor:**\ Fixed an issue where comments were being removed during execution due to auto-formatting. 6. **Authentication & Data Integrity** * Fixed expired guest token issues occurring in scheduled email reports. * Resolved duplicate column issues during MSSQL metric creation. 7. **Datamart & Metric Consistency:**\ Fixed an issue where deleted datamart columns continued to appear in the network tab, which caused custom columns to show connection errors and invalid metrics to expose the fullscreen action. **Image Version:** 1.2.16\ **Plugin Version:** 0.16.38 **DataBrain Updates: Features, Enhancements, Fixes** 📢 ### Features: 1. **Alerts:**\ We have introduced a new feature, *Alerts*, which notifies users when there is an error in the data source connection or when a datamart is broken, making the dashboard unviewable. Alerts for data source and datamart issues ### Enhancements: 1. **Color Selection from Colors Tab:**\ Users can now drag and reorder colors directly from the Colors tab. Color Selection from Colors Tab 2. **Context Window Indicator in AI Copilot:**\ Displays token usage per session (input and output). The limit varies by LLM and determines how much conversation can be retained. Once reached, the chat cannot continue. Context Window Indicator in AI Copilot 3. **Delete Datamart API:**\ Added validation and improved error messaging to prevent the deletion of datamarts that are connected to a workspace. ### Fixes: 1. **Pivot Table V3:**\ Fixed an issue where conditional formatting was not rendering when a suffix was applied. 2. **Horizontal Bar Chart:**\ Added support for the Group By functionality. 3. **Elasticsearch:**\ Fixed issues related to schema sync and index handling. 4. **Cdb:**\ Fixed an issue with the stable build for fresh installations using a new database. **Image Version:** 1.2.13\ **Plugin Version:** 0.16.35 **DataBrain Updates: Features, Enhancements, Fixes** 📢 ### Features: 1. **[Multiple Datamart Connection Support](https://docs.usedatabrain.com/guides/workspace/multi-datamart-workspace):**\ Introduced multi-datamart support, allowing users to select and manage multiple datamarts. 2. **[CRUD API Support for Semantic Layer](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/semantic-layer-api):**\ Users can now **[create](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-semantic-layer)**, **[rename and update](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-semantic-layer)**, and **[delete](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-semantic-layer)** the Semantic Layer via APIs. 3. **[Delete Workspace API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-workspace):**\ Introduced a new DELETE endpoint to enable workspace deletion via API. ### Enhancements: 1. **Pivot Table Chart V3 Calculated Fields:**\ Added support for custom calculated measures, allowing users to create and edit calculated columns. Pivot Table Chart V3 calculated fields 2. **Add Conditional Formatting Support to Pivot Table V3:**\ Introduced conditional styling with dynamic badge colors and background styles. Conditional formatting in Pivot Table V3 3. **[Refinement of List Datamarts API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-datamarts):** We have introduced an `expandDetails` option to the Datamart List API, enabling users to control the inclusion of detailed properties in responses. ### Fixes: 1. **Pagination Sync Issue in Table Charts:**\ Fixed an issue where the default row size option was not in sync with the pagination value for server-side pagination-enabled table charts. 2. **Plugin Manage Metrics: Messaging & Settings Access:**\ When all metrics are hidden, an appropriate message will now be displayed. The settings/manage metrics button remains accessible even when all metrics are hidden. 3. **Addition of Server Events in Embed:**\ Added server-side event tracking for key user actions, including metric creation/editing, data exploration (search, table selection, drag-and-drop, aggregation), chart changes, dashboard interactions (filters, manage metrics, layout), and exports/downloads. 4. **Retaining Primary Database Selection in Update Datamart:**\ Ensured that the primary database selection is preserved during the Update Datamart operation. **Image Version:** 1.2.11\ **Plugin Version:** 0.16.34 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Chart Appearance and Chart Actions Props for End Users:**\ We have added properties to the `dbn-dashboard` component that set default values for certain chart settings when a user creates a metric. Additionally, we have introduced properties for each of these settings that can lock the values, making them non-configurable for end users. 2. **Wildcard Support for OpenSearch:**\ We have introduced wildcard syntax support for datamart tables, allowing users to specify flexible patterns when creating or updating tables. 3. **Workspace LLM Configuration via API:**\ We have introduced optional LLM integration in workspace creation and update processes, allowing users to specify an LLM by name. 4. **User-Defined Click Action on Charts:**\ We have introduced a `chartClickFunction` prop to enable custom click actions on charts. The **Pass Complete Data to Function** option allows you to pass the entire row data to the function, enabling dynamic customization of the panel content through the prop. User-Defined Click Action on Charts *** **Image Version:** 1.2.10\ **Plugin Version:** 0.16.33 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Create Empty Dashboard Embed API:**\ We have introduced a prop that allows users to pass data from the Export API response when creating an empty dashboard embed. 2. **Export Embedded Dashboard API:**\ We have introduced an endpoint to export embed data, enhancing data retrieval capabilities for users. ### Enhancements: 1. **Description and Details for Embeds:**\ We have added **Description** and **Details** fields for embeds. Embed Description and Details ### Fixes: 1. We have optimized the bundle size of the plugin. **Image Version:** 1.2.9\ **Plugin Version:** 0.16.32 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Cast or Convert Datetime Columns Based on Guest Token Timezone:**\ Introduced timezone application functionality for datamart and end-user metric creation. Users can now toggle timezone adjustments for date-time columns via a new switch component in Datamart. Timezone-based Datetime Handling 2. **CRUD on CockroachDB Datasource with API:**\ Added API support to create, read, update, and delete CockroachDB datasource configurations programmatically. 3. **Readiness Endpoints for Self-Hosted Deployments:**\ Introduced health check endpoints to monitor application status. ### Enhancements: 1. **SSH Tunneling Support for Redis:**\ Introduced SSH tunneling support for Redis connections, enhancing configuration options when creating company Redis instances. SSH Tunneling Support for Redis 2. **Dynamic Adjustment of Axis Limits in Charts:**\ Users can now dynamically adjust the lower and upper limits of the vertical axis in all charts with axes. Dynamic Axis Limits in Charts 3. **Chart Actions Enhancement for Table Chart:**\ Added row redirection and column redirection options for table charts. Table Chart Actions Enhancements 4. **Enhancement of Import Dashboard API:**\ Introduced `dashboardId` and `dashboardName` as parameters in the API. 5. **Support for Reflecting Embed Name While Creating an Empty Dashboard Embed:**\ Added an optional `isRenameDashboard` parameter to the dashboard creation functions, allowing users to conditionally rename dashboards during the creation process. ### Fixes: 1. **Export as PDF Download Speed:**\ Improved performance for exporting dashboards as PDF. 2. **Alias Mismatch After Editing Metrics in Imported Dashboards:**\ Resolved an issue where aliases did not match properly when users edited metrics by adding filters or sorting. 3. **Export Dashboard API Error Handling:**\ Enhanced error handling by introducing a specific error message for invalid dashboard IDs or workspace names, improving API response clarity. 4. **Boolean Dashboard Filter in Postgres:**\ Fixed issues with boolean filters in Postgres-backed dashboards. 5. **OpenSearch Connection Issue:**\ Fixed a connection issue affecting OpenSearch. **Image Version:** 1.2.8\ **Plugin Version:** 0.16.31 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API to Whitelist Domains:**\ We have introduced a new API endpoint `whitelist-domains` to manage whitelisted domains associated with a company. 2. **API for SMTP Settings:**\ We have introduced a new API endpoint `smtp-settings` to save and update company SMTP settings, improving email configuration management. ### Enhancements: 1. **Rotate Data App API using Self Auth:**\ Updated the authentication method for Data App API key rotation from the master token to the current API key. 2. **Customization of "Exporting Dashboard" Prompt Position:**\ Added a property in the dashboard component to customize the position of the Exporting Dashboard prompt:\ `exportMsgPosition: "bottom" | "bottom-left" | "bottom-right" | "center" | "top" | "top-left" | "top-right"`. ### Fixes: 1. **Cockroach DB:**\ Resolved SSL certificate verification and date filter issues. 2. **BigQuery:**\ Fixed an issue with underlying data in the time-series chart. 3. **OpenSearch:**\ Fixed a connection issue. 4. **Datamart:**\ Added unique name constraints in app and APIs. 5. **Data App API Keys:**\ Updated to accept `expiryTime` as a string instead of a number. **Image Version:** 1.2.7\ **Plugin Version:** 0.16.30 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Create & Rotate Service Token API:**\ We have introduced service token management with two new endpoints for creating and rotating service tokens. Validation schemas have also been added for service token operations to ensure data integrity. 2. **New Data Source - Cockroach DB:**\ Support has been added for a new data source: Cockroach DB. Cockroach DB 3. **Import & Export Dashboard API:**\ API support has been added for exporting and importing dashboards. 4. **Include Metrics in Template Dashboard:**\ We have included metrics to the template dashboard for create dashboard embed API. 5. **Create Account using API:**\ We have introduced endpoints for creating self-hosted admin accounts and generating JWT tokens, enhancing support for self-hosted instances: Create Admin Account, Create Admin JWT (Self-Hosted), Reset Admin Password (Self-Hosted). ### Enhancements: 1. **Table Search Position Options:**\ Configurable search positioning has been introduced for table charts and components. Table Search Position 2. **Waterfall Chart:**\ Measures can now be treated as difference values by selecting the Difference option in the Waterfall Settings section. Waterfall Chart 3. **Fullscreen Trigger via Title Click in Embed:**\ A new prop: `enable-title-click-fullscreen={true}`, has been added to enable fullscreen mode when clicking the chart title. ### Fixes: 1. **Waterfall Chart:**\ Issues with chart labels have been resolved. 2. **ExpiryTime Type in Guest Token Creation & Rotate Token API:**\ Handling of the `expiryTime` parameter in guestToken and guestTokenV2 functions has been improved to ensure consistent data types. 3. **Invite User & Resend Mail Flow:**\ Issues in the invite user and resend mail flow have been resolved. **Image Version:** 1.2.4\ **Plugin Version:** 0.16.28 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Timezone in Query Execution from Guest Token Parameters:**\ We have implemented a feature to set timezone in query execution using guest token parameters. 2. **Added BYOD Support for CockroachDB:**\ Added BYOD support for CockroachDB (connect your own Cockroach instance). 3. **AI Suggestions for SQL Editor:**\ Connect your LLM to enable AI-powered suggestions for table names, schema names, and column names. **Image Version:** 1.2.3\ **Plugin Version:** 0.16.23 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Improved Join Handling in End-User Metric Creation:**\ Updated the join logic to apply joins only between selected tables and disabled column selection from tables that are not directly connected, reducing invalid joins and improving metric accuracy.\ For example, when a One-to-Many relationship is defined between Orders and Shipments, dragging a column from Shipments will surface only the Shipments and Orders tables for selection. (Gif 1) Improved Join Handling 2. **Revert Option to Default Date in Metric and Dashboard Filters:**\ Users can now switch back to the default date in both metric-level and dashboard-level filters. Revert to Default Date - Metric Filter Revert to Default Date - Dashboard Filter ### Enhancements: 1. **Settings Button Enhancement in Embed:**\ Added `settings-icon` prop to the `dbn-dashboard` component. `settings-icon={JSON.stringify({name: 'random',iconSvg: 'svg'})}` 2. **PDF Table Header Wrapping:**\ Enabled text wrapping for table headers when downloading dashboards as PDFs. 3. **UI Styling Support for Pivot Table V3 Chart:**\ Added UI styling options to the Pivot Table V3 chart. Pivot Table V3 Styling 4. **Dynamic Label Positioning for Waterfall Charts:**\ Labels now dynamically adjust their position based on increases or decreases in values. Dynamic Waterfall Labels 5. **Cumulative Start and End Labels for Waterfall Charts:**\ Added support for displaying cumulative start and cumulative end (running total) labels, making it easier to understand how individual increases or decreases impact the overall total. (Image 5) Cumulative Waterfall Labels 6. **Font Size Customization for Tables and Underlying Data:**\ Users can now control font sizes via Chart Settings for UI-styled table charts, and via Theme Settings for table charts and underlying data views (popup and fullscreen), ensuring improved readability and visual consistency. (Images 6, 7) Table Font Size Customization Underlying Data Font Size Customization 7. **Encryption, Headers, and Documentation:**\ Updated filter encryption to use Company ID and added `x-authorization` header support for proxy authentication keys. ### Fixes: 1. **Fullscreen and Download Metric Options in Embed:**\ Fixed an issue where Fullscreen and Download options were not visible in embedded dashboards containing merged metrics. **Image Version:** 1.2.0\ **Plugin Version:** 0.16.18 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Create Datamart API – Hide Table:** Added support for `tableList.isHide` to hide entire tables from the Datamart interface. Refer to the [Create Datamart API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datamart#:~:text=tableList.isHide,the%20datamart%20interface) documentation for details. 2. **Create Datamart API – Hide Table Column List:** Added support for `tableList.columns.isHide` to hide specific columns from the Datamart interface. Learn more in the [Create Datamart API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datamart#:~:text=tableList.isHide,the%20datamart%20interface) documentation. 3. **CRUD APIs for Datasource:** Introduced full CRUD API support for managing datasources. See the [Datasource API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datasource) documentation. 4. **Pie Chart – Measure Breakdown:** Added measure-based breakdown for Pie Charts, where wedges are generated based on the number of measures. Piechart 5. **Waterfall Chart V2:** Introduced Waterfall Chart V2 with cumulative value support. Waterfall Chart V2 6. **Multiple Scheduled Reports:** Enabled end users to create and manage multiple scheduled reports. 7. **API for Listing User-Created Reports:** Added API support to list user-created scheduled reports by embed. Refer to the [List Schedule Reports API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-schedule-reports-by-embed) documentation. 8. **Embed Renaming API:** Added API support to assign and update embed names. See the [Rename Embed API](https://docs.usedatabrain.com/developer-docs/helpers/api-reference/rename-embed) documentation. ### Enhancements: 1. **Dashboard Embed Metadata API:** Added new parameters to fetch additional embed metadata, including `createdAt`, `updatedAt`, `externalMetricId`, `dataAppId`, `embedId`, and `name`. Learn more in the List Embed API documentation. 2. **Whitelist Domain Support:** Added wildcard support and improved Top-Level Domain handling for whitelisted domains. ### Fixes: 1. **Whitelist Domain Validation:** Fixed issues related to incorrect Top-Level Domain handling in whitelisted domains. **Image Version:** 1.1.140\ **Plugin Version:** 0.16.16 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Service Tokens and API Key Rotation:** You can now create and manage service tokens within the app for improved security and API lifecycle management. This enables API key rotation directly through the Data App for safer long-term usage. 2. **Dashboard Deletion via Embed Config:** Added support for dashboard deletion using the URL parameter:`"isDeleteDashboard": true` ### Enhancements: 1. **CSV and XLSX Support in Scheduled Reports:** Users can now schedule reports in CSV and Excel (.xlsx) formats, expanding export flexibility in automated schedules. ### Fixes: 1. **Resolved Metric Loading Issue:** Fixed an issue where loading a metric caused the entire dashboard to load instead of only the selected metric. 2. **Dashboard Filters on Empty Dashboards:** Filters are now supported even on dashboards with no visualizations. 3. **Schedule Report in Embed:** Scheduling reports through embedded dashboards now works contextually based on the selected dashboard and client. **Image Version:** 1.1.139\ **Plugin Version:** 0.16.14 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Auto Joins in End-User Metric:** You can now set up auto joins in the Semantic layer. End users can drag and drop to create metrics from different tables seamlessly. **Image Version:** 1.1.137\ **Plugin Version:** 0.16.12 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Gemini LLM:** Added a new connector for LLMs — Gemini. Gemini LLM Connector 2. **User Defined Fields (UDF):** Easily customize dashboards with your own data fields — no schema changes needed. DataBrain now auto-detects and supports both common and client-specific fields as dynamic filters and chart axes for flexible, personalized insights. **Image Version:** 1.1.136\ **Plugin Version:** 0.16.8 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API Endpoint for End User Dashboard Creation**: End users can now create dashboards directly through the API. 2. **New Data Source – Trino**: Added support for a new data source — Trino. Trino Data Source 3. **Single-Click Download for Metrics Data in Embed**: End users can now download the underlying data for all metrics with one click by adding the prop:\ `enable-download-csv="true"` 4. **Fullscreen Metrics in Embed**: Metrics can now fit fullscreen in embeds using the prop:\ `shouldFitFullScreen="true"` 5. **Private & Publish End User Metric in Embed Dashboard**: You can now use `userIdentifier` inside the params object to uniquely identify end users in embedded dashboards. ### Enhancements: 1. **Customizable Fonts for Table Chart**: Added options to configure font family, font color, and font weight in table charts. Font Options for Table Chart 2. **UI Theming for Underlying Data**: Introduced settings to customize header text, background color, content text, spacing, and font weight for underlying data. UI Theming for Underlying Data 3. **Support for Label and Hide Options in Datamart & Create Metric**: You can now add labels to columns and hide columns on the create metric page by configuring them in the Datamart layer. Label and Hide Options 4. **Enhance Gantt Chart**: You can now add additional dimensions to the tooltip of Gantt charts. Enhance Gantt Chart Tooltip 5. **Variable Value Support for Next Preset Date Filter**: Added variable value support for the “Next” preset date option in metric and dashboard filters. Variable Support in Metric Filter Variable Support in Dashboard Filter ### Fixes: 1. **Percentile Continuous and Percentile Discrete**: Resolved issues with the `Partition By` and `Value` fields in the Percentile function. 2. **End User Metric Creation**: Fixed the loader issue in chart view and problems related to the distinct option in dimensions. 3. **Unpublished Metrics**: Resolved issues affecting metric listing and deletion. **Image Version** : 1.1.134\ **Plugin Version** : 0.16.2 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Boards**: Users can now create multiple views of a dashboard based on applied dashboard filters and easily switch between them. ### Enhancements: 1. **Set Default Client Per Dashboard**: Users can set a default client for each dashboard. 2. **Edit Metric**: Users can edit a metric by clicking the edit icon next to the metric name. 3. **Lifetime Option in Single Value Card**: A new option, *Lifetime*, has been added to Single Value Cards to perform aggregate calculations without comparisons. 4. **Customize Dashboard Layout in UI Theming**: Users can now configure vertical and horizontal gaps for dashboard layouts in the UI Theming page. 5. **Height-Based Auto Pagination in Table Charts**: Table charts now support automatic pagination based on height, adjusting the number of rows dynamically. 6. **Prop for Breadcrumb (Drill Down) Color and Font Family**: Users can now add color and font family to breadcrumbs when drill down is enabled in embed. 7. **Prop to Change Badge Color of Multi-Select Filter**: Introduced a property for pill color in the multi-select badges in embed. ### Fixes: 1. **Updated Results Table for No Data**: The image displayed when a query returns no results in the Query Builder has been updated. 2. **Drill-Down Issue with Unselected Dimensions**: Fixed an issue where an unselected dimension appeared in the drill-down hierarchy. 3. **Date Filter Font Consistency**: Fixed font inconsistencies in date-based metric filters. **Image Version** : 1.1.131\ \*\*Plugin Version \*\*: 0.15.150 **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **'percentile\_cont' and 'percentile\_disc' Functions for Measures**: You can now calculate continuous and discrete percentiles using these new functions. 2. **Download Dashboard as PDF**: Users can now download dashboards in PDF format. 3. **Dropdown Multi-select Filter for String Columns in Table Chart**: A dropdown multi-select filter can now be added to any string column in a table chart. 4. **Trendline Support**: We have introduced trendline functionality in table charts using custom SQL. *** ### Fixes: 1. **Default option for LLMs**: You can now set any LLM as the default option. 2. **Metric Filter Styling Issue**: Fixed font and font size inconsistencies in date-type metric filters. 3. **Underlying Data Download in OpenSearch**: Resolved issues related to downloading underlying data in OpenSearch. \*\*Image Version \*\*: 1.1.129\ \*\*Plugin Version \*\*: 0.15.143 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **API Endpoint for Datamart**: Users can now perform CRUD operations on datamarts using the API endpoint. 2. **Hybrid (Stacked + Bar) Chart**: A new chart type, *Hybrid Bar*, has been introduced. *** ### Enhancements: 1. **Metric Filter Interaction**: Improved workflow for switching between 'Apply On' and 'Filter Options' in Metric Filters for smoother navigation. 2. **Gantt Chart Styling**: Added bar styling options for Gantt Chart, including Bar Height, Top Radius, and Bottom Radius. *** ### Fixes: 1. **Scheduled Report Issues**: Resolved the "No Data Found" and layout issues in scheduled reports. 2. **Gantt Chart**: Fixed date format issues in the Gantt chart. 3. **Hide App Filter in Filter Box**: The App Filter is now hidden in the dashboard switch select filter to enhance security and ensure proper functionality. **Image Version**\ : 1.1.122\ , **Plugin Version**\ : 0.15.136 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Gantt Chart**: Introducing the Gantt Chart for enhanced timeline-based visualization of tasks and projects. 2. **Y Axis - Log Scale**: Added the ability to convert the Y-axis to a logarithmic scale for improved visualization of wide-ranging values. 3. **Click Action on Single Value Card**: Enable interactive experiences by configuring click actions on Single Value Cards. 4. **New Data Source - OpenSearch**: Now supporting OpenSearch as a data source, expanding your integration options. 5. **Optional Variable Filters**: Variable filters can now be made optional using square brackets in code blocks for greater flexibility. ### Enhancements: 1. **Underlying Data Download**: Added support to download filtered underlying data for deeper offline analysis. 2. **Badge Color in Table Chart**: Introduced the ability to set badge colors in table chart conditional formatting. ### Fixes: 1. **Switch Select Default Value**: Resolved inconsistencies in Switch Select options by setting a default value. 2. **Dynamic Properties in Descriptive Elements**: Fixed loading issues in dynamic properties across footnote, title, description, and long description. 3. **Athena Load Time Disparity**: Addressed inconsistencies in load time between Query Editor and Chart Builder for Athena data source. **Image Version**\ : 1.1.119\ , **Plugin Version**\ : 0.15.130 **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Drill Down Revamp**: We've updated the UI of Drill Down Feature to ensure better clarity and visibility. 2. **Custom SQL Revamp**: We've enhanced the Custom SQL interface to offer a cleaner editing experience and improved validation feedback for better query building. Users can write custom SQL queries and save them as Table Chart, Table Chart with Dynamic Table, New Chart or Custom Dataset. 3. **Single Value Card**: We've added alignment and font options, along with dynamic property support for sub-header text in the Single Value Card. String-based conditional formatting support has also been introduced. 4. **Metric Border Color**: Users can now specify the metric border color globally from the UI Theming page. ### Fixes: 1. **Filter Disappearance on Sync in Metric Page**: Resolved an issue with the variable metric filter for the Redshift data source. 2. **Custom Columns in Simple Filter**: Fixed an issue where custom columns were not appearing in the simple filter. **Image Version**\ : 1.1.116\ , **Plugin Version**\ : 0.15.127 **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Background Color Option for Metric Summary**: You can now set a background color for the metric summary card. 2. **Delete Option for Custom Roles**: A delete option is now available for custom roles. 3. **Chart settings for chart title, axis labels, axis values, and legend** have been added globally under the 'UI Theming' section on the Embed Settings page. ### Fixes: 1. **Download data issue in Athena data source**: Resolved an issue with downloading data in metrics and when limit is applied. 2. **Logo in Scheduled Reports**: Resolved an issue with the logo in scheduled reports. 3. **Switch Y Axis Enablement with Individual Number Formatting**: When the "Switch Y-Axis" option is enabled, each measure now correctly applies its own number formatting settings. **Image Version**\ : 1.1.108\ , **Plugin Version**\ : 0.15.122 **DataBrain Updates: Enhancements, Fixes** ### Enhancements: 1. **Date Restriction Feature in Preset Date Dashboard Filters**: We have added an "Enable Restrictions" toggle to the Preset Date Dashboard filter, similar to the Metric Filter. 2. **OIDC Identity Provider (IDP) Support**: Users can now create an OIDC-based IDP for Single Sign-On (SSO) under MFA & SSO Settings ### Fixes: 1. **Dashboard UI Fix**: Resolved an issue where the 'Reset' button overlapped with other UI elements on the dashboard page. 2. **Report Scheduling**: Added user prompts for improved clarity and guidance during report scheduling. **Image Version**\ : 1.1.106\ , **Plugin Version**\ : 0.15.120 **DataBrain Updates: Features, Enhancements, Fixes** ### Features: 1. **Add Alignment Option for Single-Value Card**: You can now align the value in Single-Value Cards.\ Navigate to Settings > Appearance > Customizations > Alignment for more control over layout. 2. **New Data Source – Athena**: We've added support for a new data source: Athena 3. **Horizontal Combo Chart**: A new chart type has been introduced, similar to the combo multi-scale chart but arranged horizontally. 4. **Bubble Chart V2**: The updated version of the Bubble Chart now allows users to specify bubble size. You can now set a measure for bubble size and drag & drop measures into dimensions. ### Enhancements: 1. **Date Range Mapping for Single Value Card Comparison**: Single value cards now automatically reflect the selected dashboard date filter range. If "Lifetime" is chosen, the card uses the comparison value set in its settings. 2. **Grid Dividers in Merge Metric**: Users can now add grid dividers between different metrics and enhance them with background colors. ### Fixes: 1. **Download Array Datatype Column Values**: Fixed an issue where array-type column values were not downloaded correctly. 2. **Single Value Card Resizing**: Resolved inconsistencies in resizing behavior for Single-Value Cards. 3. **Progress V2 Number Formatting**: Addressed incorrect number formatting on upper limit when using dynamic properties. 4. **Combo Chart Duplicate Axis**: Fixed an issue where duplicate axes appeared in Combo Charts. 5. **Resolved an issue with the preset date dashboard filter in Firebolt.** **Image Version**\ : 1.1.102\ , **Plugin Version**\ : 0.15.116 **DataBrain Update: Enhancements** ### Enhancements 1. **Complex Sort in Metrics**: Added a feature to generate SQL for custom sorting beyond the default lexicographical ASC and DESC provided by SQL. 2. **Role Permissions for Metric Elements**: Introduced an option to manage role-based permissions for metric elements. 3. **"All Clients" Option**: Added an "All Clients" selection on the metric creation page. 4. **Transpose Data in Table Charts**: Introduced a toggle to switch rows and columns in table charts. **Image Version**\ : 1.1.101\ , **Plugin Version**\ : 0.15.113 **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Metric Expression Support in Elements**: We have introduced metric expression support in elements, allowing users to compute values using metric ID. 2. **Added Variable Filter for Preset Date Filter**: Implemented a variable filter in the preset date option for dashboards. ### Fixes 1. **Improved Pagination on the Explore Data Page**: Fixed an issue where pagination did not display correctly, ensuring a smoother navigation experience. 2. **UI Update**: Resolved an issue with tooltips for better usability. **Image Version**\ : 1.1.100\ , **Plugin Version**\ : 0.15.111 **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Font Style Options in Axis Charts**: Added Font Family, Font Size, and Font Weight options for horizontal and vertical axis names 2. **Font Styling for Metric AI Summary**: Users can now customize font styles in the Metric AI Summary 3. **Text Wrap in Combo Multi-Scales Chart**: Users can now define a value to break text in the Y-axis name of the combo multi-scales chart 4. **Customize Date Format**: Users can now set their preferred date format for the date filter in the "UI Theming" page ### Fixes 1. **Explore Data**: Fixed a download issue in the Explore Data feature **Image Version**\ : 1.1.99 , **Plugin Version**\ : 0.15.107 **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Sorting and Number Formatting for Pivot Table V2**: Added options for sorting and number formatting in Pivot Table V2 2. **Custom Value Redirection in Table Chart**: Users can now click on a specific value in the Table Chart to be redirected to a designated link ### Fixes 1. **UI Update**: Chart Tooltip settings will remain hidden until the "Label Tooltip" toggle is enabled 2. **Metric Alignment Fix**: Resolved an issue where metric alignment changed after exporting and importing a dashboard. **Image Version**\ : 1.1.98, **Plugin Version**\ : 0.15.104 **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Editability of Created Views in Custom Datasets**: Exploring the feasibility of enabling editing and deleting capabilities for previously created views within custom datasets. 2. **Enhanced Pivot Table V3**. 3. **Improved UI for Table Chart Pagination.** 4. **Metric Background Color in Single Value Card**: Users can now add a background color to Single Value Cards. 5. **Set Config**: User can now set Data Config Options in Embedded Dashboards. ### Fixes 1. Fixed flickering issue in bar charts. 2. **BigQuery Data Source Fixes**: Resolved issues with GROUP BY, single quotes in filters, and AI-powered query formatting. **Image Version**\ : 1.1.96\ , **Plugin Version**\ : 0.15.102 **DataBrain Update: Features, Enhancements & Fixes** ### Features 1. **Auto Format Custom SQL with AI**: Introduced an AI-powered feature for automatically converting custom SQL queries into DataBrain's preferred format, ensuring consistency and improved query management. ### Enhancements 1. **Multiple Dependencies in Metric Filters**: Users can now add multiple dependencies between metric filters for greater flexibility. 2. **Conditional Band Formatting for Horizontal Bar Chart**: Allows users to apply custom band colors based on defined ranges, enhancing visual clarity. 3. **Font Weight Dropdown**: Added a dropdown to select font weights for text values, enhancing readability and customization. 4. **Improved User Experience in "Manual" Dashboard and Metric Filter**: The mandatory fields ‘Option Value’ and ‘Option Label’ now appear by default, eliminating the need to manually click ‘+ Add Option.’ 5. **Added Range Option Type in Metric Filter**: Enables users to specify a range of values for improved filtering flexibility. 6. **Text Wrapping in Table Chart Columns**: Introduced text wrapping for better readability in table charts. 7. **Column Resizing in Table Chart Without Table Header**: Users can now resize columns, regardless of whether the table header is hidden. ### Fixes 1. **Escape Filter Values with Single Quotes**: Metric filters now properly accept values containing single quotes. **Image Version:** 1.1.94\ **Plugin Version:** 0.15.99 **DataBrain Update: Enhancement** ### Enhancement 1. **Added options in preview link**: Users can now control the side panel and dashboard name in the preview link generation. **Image Version**\ : 1.1.93\ , **Plugin Version**\ : 0.15.98 **DataBrain Update: Features, Enhancements & Fixes** ### Feature 1. **Datasource Sync API**: Exposed an API for syncing the datasource ### Enhancements 1. **Dashboard Date Filter & Time-Series Chart Integration**: We have added support for mapping dashboard date filter options with time-series charts for improved synchronization 2. **Bar Styling for Combo Multi-Scales Chart**: Added a "Bar Styling" option to the combo multi-scales chart for better customization. This feature allows users to fine-tune the appearance of bars for improved visualization and readability with key Customization Options: * Bar Width – Adjust the width of bars to control spacing and visual clarity * Bar Top Radius – Round the top edges of bars for a softer, modern look * Bar Bottom Radius – Customize the bottom edge roundness for a polished appearance ### Fixes 1. **Bubble Chart in Firebolt**: Resolved an issue affecting the Bubble chart when using the Firebolt datasource 2. **UI Update (Fullscreen Dropdown Component)**: Fixed an inconsistency in dropdown behavior when in fullscreen mode **Image Version**\ : 1.1.92\ , **Plugin Version**\ : 0.15.96 **DataBrain Update: Enhancements & Fixes** ### Enhancements 1. **Horizontal Chart**: Added Switch X-Axis and Switch Y-Axis features for improved flexibility 2. **Sankey Chart**: Introduced Switch Measure functionality for better customization ### Fixes 1. Resolved an issue where the Switch X-Axis Dropdowns displayed removed dimension values 2. Fixed duplicate values appearing in the Filter Panel dropdown in Custom Query Mode **Image Version**\ : 1.1.91\ , **Plug In version**\ : 0.15.94 **DataBrain Updates: Features, Enhancements, Fixes** ### Features 1. **Rearrange Metric Filters**: You can now rearrange metric filters on the update/create metric page using drag-and-drop, making customization easier and more intuitive. 2. **Save a Custom Dataset (View) to Multi-Selected Datasource**: You can now save a custom dataset across multiple selected data sources, enabling seamless data management and greater flexibility. Refer to the document below:\ [Creating a custom dataset view](https://docs.usedatabrain.com/guides/datasources/creating-a-custom-dataset-view-in-a-multi-datasource-environment) 3. **Support Fiscal Year in Date Filter**: You can now set up a custom fiscal year filter in DataBrain to filter data based on the Indian Financial Year. Refer to the documentation below:\ [Custom Fiscal Year Filter Setup](https://docs.usedatabrain.com/developer-docs/helpers/options/custom-fiscal-year-filter-setup-in-databrain) 4. **Easier Access to Frequently Used Tables**: Frequently used tables now appear at the top of the schema sidebar on the metric creation page, improving accessibility and efficiency. ### Enhancements 1. **Adaptive formatting for Indian decimals**: The Indian Number System now considers values up to two decimal places. 2. **Enhanced Chart Controls for End Users**: End users can now access additional chart options, including Enable Cumulative Behavior, Dynamic Behavior, and Chart Zoom, for improved data visualization and interaction. ### Fixes 1. **UI update**: We have enhanced the user experience by eliminating flickering when switching between the Charts Panel and Settings Panel, ensuring a smoother and more seamless transition. 2. **Improved Reset Password Flow**: Expired Reset Password links now immediately display a “Reset Password Link Expired” message, preventing unnecessary input. 3. **Date filter**: The Date Filter now accepts only four-digit years, preventing incorrect inputs. **Image Version**: 1.1.89\ **Plug In version**: 0.15.87 **DataBrain Updates: Features, Enhancements, Fixes** ### Features 1. **Drill Down for Tree Map**: Introducing drill-down functionality in Tree Map charts! Click on a section to explore deeper levels of data effortlessly. 2. **Chart Click Action with Metric**: Now, clicking on a metric within a chart allows seamless navigation to another related metric for enhanced data exploration. 3. **Add View Button in Table Chart**: Added a "View" button in table charts, enabling users to expand selected columns within a row for better data visibility. 4. **Add RHS Custom SQL Support**: Added the ability to control how selected options from a dashboard dropdown are applied on the RHS of the `WHERE` clause. Use the `{{global_selected_values}}` variable to modify selected values dynamically (e.g., applying transformations like `CONCAT`). 5. **End users can now archive metrics** ### Enhancements 1. **Adaptive Formatting – Indian Number System**: Added support for number formatting in the Indian system (e.g., lakh, crore) for improved readability. 2. **Copy Generated SQL with One Click**: A new "Copy" button allows you to easily copy the generated SQL query. 3. **Customizable Color Palettes**: Modify colors in existing palettes anytime to match your theme by clicking on the edit icon. ### Fixes 1. **Side Panel UI**: Addressed display inconsistencies in the join panel, resolving issues with overflowing fields for a cleaner user experience. 2. **Time-Series Chart**: Resolved an issue where the chart headers were not displaying correctly in metric full-screen mode. 3. **Workspace Panel**: Fixed scrolling issues for a smoother and more seamless user experience. 4. **Combo Option in Time-Series Chart**: Resolved an error that occurred when using the combo option in the time-series chart. **Image Version**: 1.1.86\ **Plugin Version**: 0.15.82 **Features, Enhancements, Fixes:** ### Features: 1. **Footnote as a Rich Text Box**: Footnotes are now powered by a React text box, allowing you to add links, change colors, and apply formatting like bold and italics for better customization. 2. **Hide Dashboard Filter in Embed Code**: You can now control the visibility of dashboard filters in embedded dashboards. This is useful for cases where different user groups need different filter options. For example, US customers can see the US fiscal year, while Indian customers see the Indian fiscal year—without displaying unnecessary filters. Please refer the below link: Options\ The extra options/parameters that you can pass for your Web Component. 3. **Cumulative Option for Line and Area Charts**: A new "Cumulative" option has been added to Line and Area charts, accessible under Chart Settings > Appearance > Features > Cumulative for better trend analysis. 4. **SDK Overrides**: Now you can override card titles, descriptions, footnotes, column names (for tables), and label/legend names (for charts) directly in the SDK for enhanced customization. Please refer the below link: Options\ The extra options/parameters that you can pass for your Web Component. 5. **New Progress Bar Chart and Geo Region Map**: Added two new charts, Improved Progress Bar and Geo Region Map for Indian States. 6. **Merge Layouts**: Easily merge multiple metrics and rearrange them with the same flexibility as the dashboard's custom layout. 7. **Preview Link Management**: Track all preview links generated for dashboards and delete those no longer needed for better link management. ### Enhancements: 1. **UI Theming Update**: You now have the option to remove the stroke around metric cards for a cleaner visual experience. 2. **Revamped Chart Panel in Create Metric Page**: Charts are now grouped under categories, making it easier to find and search for the desired visualizations. 3. **Dynamic Property Support**: Added support for dynamic property implementation in the lower and upper limit setup. 4. **Clear All Option**: Easily clear all columns added in measures or dimensions with a single click using the "Clear All" functionality. **Image Version**: 1.1.77\ **Plugin Version**: 0.15.65 **Features, Enhancements, Fixes:** ### Enhancements: 1. **Donut Chart**: Added the ability to switch X and Y axes for enhanced customization. 2. **Dynamic Property Support**: Metrics created using Python now support dynamic properties for greater flexibility. 3. **Box Plot**: Enhanced Box Plot to support multiple experiments, enabling richer comparative analysis. ### Fixes: 1. **Radial Charts**: Fixed the legend scrolling issue for a smoother user experience.
**DataBrain Update: Features, Enhancements & Fixes** ### Features 1. **Auto Format Custom SQL with AI**: Introduced an AI-powered feature for automatically converting custom SQL queries into DataBrain's preferred format, ensuring consistency and improved query management. ### Enhancements 1. **Multiple Dependencies in Metric Filters**: Users can now add multiple dependencies between metric filters for greater flexibility. 2. **Conditional Band Formatting for Horizontal Bar Chart**: Allows users to apply custom band colors based on defined ranges, enhancing visual clarity. 3. **Font Weight Dropdown**: Added a dropdown to select font weights for text values, enhancing readability and customization. 4. **Improved User Experience in "Manual" Dashboard and Metric Filter**: The mandatory fields ‘Option Value’ and ‘Option Label’ now appear by default, eliminating the need to manually click ‘+ Add Option.’ 5. **Added Range Option Type in Metric Filter**: Enables users to specify a range of values for improved filtering flexibility. 6. **Text Wrapping in Table Chart Columns**: Introduced text wrapping for better readability in table charts. 7. **Column Resizing in Table Chart Without Table Header**: Users can now resize columns, regardless of whether the table header is hidden. ### Fixes 1. **Escape Filter Values with Single Quotes**: Metric filters now properly accept values containing single quotes. **DataBrain Update: Enhancement** ### Enhancement 1. Added options in preview link: Users can now control the side panel and dashboard name in the preview link generation # Getting Started Source: https://docs.usedatabrain.com/developer-docs How to Seamlessly Embed a DataBrain Dashboard To embed a DataBrain dashboard into your application, we offer a straightforward approach using the DataBrain *npm* package. Simply install this package, and then bring it into your application to access a range of components. These components enable you to display full dashboards or specific metrics as needed. **Prefer using an AI assistant?** The Databrain MCP server lets you set up embeds, query data, and customize dashboards through natural language — in Cursor, Claude, Windsurf, or any MCP-compatible client. [Get started in 2 minutes →](/developer-docs/mcp-server/quickstart) ## Multi-Tenancy Support DataBrain supports embedding for different levels of tenancy based on how your client data is organized. Whether you separate data at the **table level** (rows identified by a client ID), **schema level**, **database level**, or across multiple datasources, DataBrain can handle your tenancy model. Common tenancy models include: * **Single Table Tenancy**: All client data in one table, separated by a `client_id` column * **Multi-Level Tenancy**: Combining multiple layers (e.g., schema + table, database + schema) Choose the right tenancy model based on your data architecture. Learn more about [choosing the right tenancy model](https://docs.usedatabrain.com/guides/onboarding-and-configuration/choosing-the-right-tenancy-model-for-your-data) and how to [configure tenants](https://docs.usedatabrain.com/guides/datasources/configure-tenants). *** We've got you covered with a step-by-step guide here to help you integrate DataBrain dashboards into your user interface seamlessly. ## Step-by-Step Guide to Embed DataBrain Dashboard ```bash theme={"dark"} npm install @databrainhq/plugin ``` ```js theme={"dark"} import '@databrainhq/plugin/web'; ``` For embedding a Dashboard ```html theme={"dark"} ``` or For embedding a Metric Card ```html theme={"dark"} ``` **Finding Your IDs** * **Dashboard ID**: In your Data App, navigate to **Embed Info** > **Add New Embed**. Select **workspace name**, choose embed type as **dashboard**, and select the dashboard. The **Embed ID** displayed is your dashboard ID. [See detailed guide here](https://docs.usedatabrain.com/developer-docs/helpers/dashboard-id). * **Metric ID**: In your Data App, go to **Embed Info** > **Add New Embed**. Provide the **workspace name**, select embed type as **metric**, choose the **dashboard** containing your metric, then select the metric. The **Embed ID** shown is your metric ID. [See detailed guide here](https://docs.usedatabrain.com/developer-docs/helpers/metric-id). **Token** The [`token`](https://docs.usedatabrain.com/developer-docs/token) should be a **guest token** generated from your backend using DataBrain's REST API. Each guest token is unique and ensures secure access control. **Generating a Guest Token:** Make a POST request from your backend to generate the guest token: **Cloud DataBrain:** ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/guest-token/create ``` **Self-hosted DataBrain:** ```http theme={"dark"} POST /api/v2/guest-token/create ``` **Request Headers:** ```json theme={"dark"} { "Authorization": "Bearer [API_TOKEN]" } ``` **Minimum Request Body:** ```json theme={"dark"} { "clientId": "id", // Use "None" if no tenancy selected "dataAppName": "dataappname" } ``` The API will return a token that you pass to your frontend. The token can include additional parameters like `appFilters`, `dashboardAppFilters`, and `permissions` for fine-grained control. If `expiryTime` is not specified, the token won't expire. Learn more about [token generation and advanced options here](https://docs.usedatabrain.com/developer-docs/token). **Example for Embedding Dashboard:** Here is an example with a sample token and dashboardId that you can use in your frontend app to get started without a backend: ```html theme={"dark"} ``` ## Additional Resources and Customization * **Customizing the Look and Feel**: * For further customizations related to the appearance of the embedded elements, [***refer here.***](https://docs.usedatabrain.com/developer-docs/helpers/options) * **Understanding the Overall Architecture**: * For a comprehensive understanding of the overarching architecture and how embedding fits into it, [***refer here.***](https://docs.usedatabrain.com/developer-docs/embedding-setup/architecture-deep-dive) With these steps, embedding DataBrain dashboards or metrics into your application can be done efficiently, offering a dynamic and insightful data visualization component to your users. # Token API v1 → v2 Migration Source: https://docs.usedatabrain.com/developer-docs/api-migration-guide Guide for migrating existing integrations for generating token from API v1 to v2, covering differences, deprecations, and implementation steps. **Note**: v2 is mostly compatible with v1, with only slight differences in endpoint paths and some parameter naming/placement. ### Endpoint URL Changes * v1 ``` POST https://api.usedatabrain.com/api/v1/guest-token/create ``` * v2 ``` POST https://api.usedatabrain.com/api/v2/guest-token/create ``` **Note** : The url remains same except in place of v1 it will be v2. ### Parameter Adjustments In API v1, tokens were generated using the `clientId` along with `workspaceName` and `datasourceName`. In API v2, this has been simplified by introducing a `dataApp`, so you only need to pass the `clientId` and `dataAppName`. The main change is that v2 replaces the separate workspace and datasource parameters with a single dataApp reference. * v1 example request body: ``` { "clientId": "your-client-id", "workspaceName": "your_workspace", "datasourceName": "your_datasource", } ``` * v2 example request body: ``` { "clientId": "your-client-id", "dataAppName": "your_data_app", } ``` **Note**: In both v1 and v2, the authorization parameter works the same way. The only difference is that in v1 you used the API token from global settings, while in v2 you must use the API token generated within the dataApp. This ensures that authorization is scoped specifically to the dataApp. ### Permissions * In v1, we used to set permissions in the workspace settings for creating metric, updating metric, deleting metric etc. * In v2, all these permission needs to be enabled in the specific dataApp itself. ### Create Metric * In v1, we used to just enable the create metric option in workspace settings and chose the power mode option. image.png * In v2, you first create a \*\*datamart \*\*from the same datasource you previously used in **v1**. Then, when enabling permissions like *create metric*, you reference that datamart within the dataApp settings. Screenshot2025 09 01171232 Pn ### Migration & Token Compatibility * Both v1 and v2 tokens will continue to work with the same dashboard ID. * However, note that settings applied using v1 tokens will not apply when using v2 tokens, and vice versa. * Each version’s settings are independent, even though the tokens can coexist. # Step 1: Create Datamart and Workspace Source: https://docs.usedatabrain.com/developer-docs/chat-mode/step-1-create-datamart-and-workspace To utilize chat mode in your embed, you need to first create a datamart assuming you already created a data source. Navigate to the **"Data"** section in app. Look for the **"Datamarts"** option and click on it. Click on **"Create New Datamart"** which will open a modal. Provide a name for your datamart and the datasource. Check the box if multi-tenancy is required to enable database tenancy. Click **"Next"** to proceed. On the next screen, you'll see a list of available tables. Review the list and select the tables you want to include in your datamart. Click **"Next"** to move to the column configuration. For each selected table, you'll see a list of available columns. Choose the specific columns you want to include in your datamart. You may have options to rename columns or set data types if needed. Once you've configured all desired columns, click "Next" to continue. On the **tenancy configuration** screen, you'll set up how data is separated for different tenants. Configure all tenancy-related settings. Review your tenancy configuration to ensure it meets your requirements. Click **"Complete"** to complete the datamart setup. Now, go to home page and click on + icon near **workspaces**. Enter the name for the workspace, select data connection as Data Mart and chose the datamart in the select datamart dropdown that you created and provide description if you want. Click on **"Save"** to create the workspace. **Programmatic setup:** You can also configure the semantic layer for your datamart via the [Semantic Layer API](/developer-docs/helpers/api-reference/semantic-layer-api) — useful for automating datamart enrichment in CI/CD pipelines or managing semantic metadata across environments. # Step 2: Create Data App and Embed ID Source: https://docs.usedatabrain.com/developer-docs/chat-mode/step-2-create-data-app-and-embed-id Configure a data app with AI Chat Mode by enabling access control, setting up semantic layer integration, and generating embed credentials for chat-enabled analytics. * Navigate to the "Data" section in your app. * Look for the "Data Apps" option and select it. * Click on **"New Data App"** button. Provide the required information including naming it and configuring basic settings. Access Control is crucial for managing what users can do within your Data App. Navigate to the "Access Control" tab within your created Data App. * Look for options related to "Metric Creation" and "Chat Mode". * Enable the setting that allows users to create metrics and select chat mode. * Select the Data Mart and provide the client column for each table. * Click on "Save" to save the settings. Once access control settings are configured, click on **"Embed Info"** tab in the sidebar. Refer to "Dashboard ID" for generating embed ID and refer "API TOKEN" for generating API token that will be used to generate **"guest token"** later. Once API Token is generated, create "guest token" with **"client ID"**. * Guest tokens are used for allowing temporary, limited access to your Data App. * Go to postman or any other API platform. * Set the URL as [Guest Token API Endpoint](https://api.usedatabrain.com/api/v2/guest-token/create). * In the Authorization tab, select type as **"Bearer Token"** and in token field add the "API token" that you created in your data app. * You'll need to specify a **Client ID** , which is a unique identifier for the client or user you're creating the token for and the **data app name** that you created above in the body. * Click on **"Send"** . The generated guest token will be associated with the provided Client ID and data app. Use the guest token and the embed ID to test your embed. Click on **"Chat Data"** button and start analyzing your data. To verify your response, got to **"Data"** tab in your app, select **"Semantic Layer"** in the side bar, and click on the **"Lab"** button next to the datamart that you chose to create your data app. Inside the semantic layer for you datamart, click on **"Logs"** tab. There you will see your response. # Self-Hosted Deployment Verification Source: https://docs.usedatabrain.com/developer-docs/deployment-verification Use this Docker image to verify your self-hosted application. It runs a comprehensive verification script to ensure your deployment is successful. Authenticate your Docker CLI to AWS ECR before pulling the image. ```bash theme={"dark"} aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/databrain ``` Go to public ECR: DataBrain Test Container on AWS ECR Gallery ```bash theme={"dark"} docker pull public.ecr.aws/databrain/dbn-test:1.1.9 // use newest tag ``` The container expects some environment variables to be passed for the test to work. ```yaml theme={"dark"} version: '3.8' services: test-runner: image: public.ecr.aws/databrain/dbn-test:1.1.9 // use newest tag environment: TEST_HOST: https://your-selfhosted-url.com TEST_DEMO_HOST: https://your-selfhosted-url.com/demo TEST_DEMO_TOKEN: 537ks6v3-8614-c535-4870-d47730bd0c70&dashboardId=selfhosted-dashboard TEST_USER_EMAIL: selfhosted@company.com TEST_USER_NAME: CompanyName TEST_DELETE_USER_AUTH_TOKEN_SELFHOSTED: delete_token_9so$sm TEST_USER_PASSWORD: Company@123 TEST_NEW_USER_COMPANY: newCompanyName TEST_NEW_USER_EMAIL: newselfhosted@company.com TEST_NEW_USER_NAME: newSelfhosted TEST_NEW_USER_PASSWORD: newSelfhosted@123 TEST_NEW_USER_RESET_PASSWORD: resetSelfhosted@123 TEST_ROLE_USER_EMAIL: newUser@company.com restart: "no" ``` Run the following GitHub Action step to execute application tests via Docker: ```yaml theme={"dark"} - name: Run Application Tests via Docker run: | docker run --rm \ -e TEST_HOST=${{ secrets.TEST_HOST }} \ -e TEST_DEMO_HOST=${{ secrets.TEST_DEMO_HOST }} \ -e TEST_DEMO_TOKEN=${{ secrets.TEST_DEMO_TOKEN }} \ -e TEST_USER_EMAIL=${{ secrets.TEST_USER_EMAIL }} \ -e TEST_USER_NAME=${{ secrets.TEST_USER_NAME }} \ -e TEST_DELETE_USER_AUTH_TOKEN_SELFHOSTED=${{ secrets.TEST_DELETE_USER_AUTH_TOKEN_SELFHOSTED }} -e TEST_USER_PASSWORD=${{ secrets.TEST_USER_PASSWORD }} \ -e TEST_NEW_USER_COMPANY=${{ secrets.TEST_NEW_USER_COMPANY }} \ -e TEST_NEW_USER_EMAIL=${{ secrets.TEST_NEW_USER_EMAIL }} \ -e TEST_NEW_USER_NAME=${{ secrets.TEST_NEW_USER_NAME }} \ -e TEST_NEW_USER_PASSWORD=${{ secrets.TEST_NEW_USER_PASSWORD }} \ -e TEST_NEW_USER_RESET_PASSWORD=${{ secrets.TEST_NEW_USER_RESET_PASSWORD }} \ -e TEST_ROLE_USER_EMAIL=${{ secrets.TEST_ROLE_USER_EMAIL }} \ public.ecr.aws/databrain/dbn-test:1.1.9 ``` # Embed using iFrame (Not Recommended approach) Source: https://docs.usedatabrain.com/developer-docs/embed-using-iframe-not-recommended-approach You can embed the dashboard or metric using iFrame in your app. ## Embed using iFrame (Not Recommended approach) ### Usage #### Quick Usage ```html theme={"dark"} Document ``` You would require to generate the demo URL first. For eg: ```bash theme={"dark"} https://demo.usedatabrain.com/?token="your guest token"&dashboardId="dashboard id"&embed=true ``` For generating the required params see: Make sure to add `embed=true` at the end of the URL, to embed the dashboard or metric in iFrame. # Architecture Deep Dive Source: https://docs.usedatabrain.com/developer-docs/embedding-setup/architecture-deep-dive Technical deep-dive into DataBrain's embedding architecture, authentication, performance, and deployment patterns **For Technical Teams:** This guide provides detailed technical documentation of DataBrain's embedding architecture, including authentication flows, query execution paths, performance optimizations, and advanced deployment patterns. **Prerequisites:** * Familiarity with REST APIs and authentication concepts * Understanding of database query execution * Basic knowledge of cloud infrastructure (for deployment sections) **Looking for conceptual overview?** See [Embedding Architecture Concepts](/getting-started/core-concepts/embedding-architecture) for high-level understanding. *** ## Authentication & Security Flow ### Token Generation Process Authentication Flow Diagram The authentication flow ensures secure, multi-tenant access through stateless guest tokens: **Step 1: Your backend authenticates with DataBrain** ```javascript theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/guest-token/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.DATABRAIN_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: user.tenantId, dataAppName: 'customer-portal', expiryTime: 3600000, // 1 hour params: { rlsSettings: [ { metricId: 'metric_123', values: { customer_id: user.customerId } } ] } }) }); const { token } = await response.json(); ``` Your API key should only be used server-side. Never expose it to the frontend. **Step 2: DataBrain validates every request** When the web component makes requests, DataBrain performs multiple security checks: 1. **Token lookup**: The token (an opaque UUID issued server-side) must exist in the deployment — fails with `INVALID_TOKEN` otherwise 2. **Expiration check**: Ensures token hasn't expired (`TOKEN_EXPIRED`) 3. **Origin validation**: Verifies request comes from whitelisted domain (`UNAUTHORIZED_ORIGIN`) 4. **Permission check**: Validates access to requested dashboard/metric (`UNAUTHORIZED` / `INVALID_ID`) 5. **RLS application**: Applies row-level security rules If any validation fails, the request is rejected with an appropriate error code. **Step 3: Configure allowed domains** In DataBrain dashboard, whitelist scheme-less `host[:port]` entries that can embed your analytics: * `app.yourcompany.com` * `dashboard.yourcompany.com` * `localhost:3000` (for development) Requests from non-whitelisted domains are automatically blocked, even with valid tokens. **Step 4: Row-level security enforcement** The `rlsSettings` you define in the guest token are enforced server-side per metric — the values are fixed at mint time and cannot be changed by the end user. ```json theme={"dark"} // Defined in the guest token "params": { "rlsSettings": [ { "metricId": "metric_123", "values": { "tenant_id": "customer-123" } } ] } ``` RLS and token filters are **not** a substitute for the Datamart's tenant filter, and tenant scoping is not applied uniformly to every query. Builder (visual/dataset) metrics get the tenant filter injected automatically when the Datamart's Client ID mapping is set — but **custom SQL metrics do not**: their authors must reference the tenant variable explicitly (`WHERE client_column = 'client_id_variable'`), or the metric runs unscoped. See the [Tenancy Model](/developer-docs/tenancy-model) for the full rules. ### Security Best Practices * Store API keys in environment variables * Never expose API keys in frontend code * Rotate API keys periodically * Use separate keys for dev/staging/production * Set reasonable expiration times (1-24 hours) * Refresh tokens before expiration * Generate new tokens on user session refresh * Shorter expiry = better security * Whitelist only necessary domains * Remove development domains in production * Use HTTPS in production (required) * Review whitelist regularly * Define RLS rules for all tables * Test RLS rules thoroughly * Use parameterized queries * Avoid SQL injection vulnerabilities *** ## Data Flow Architecture ### Query Execution Path Understanding how queries flow through the system: End user interacts with embedded dashboard: * Applies filters * Changes date ranges * Drills down into data * Refreshes metrics Web component constructs authenticated API request with the guest token and sends it to DataBrain to fetch metric data with any applied filters. DataBrain processing pipeline: 1. **Validate token**: Look up the token server-side; check expiration, permissions 2. **Retrieve metric**: Load metric configuration from metadata 3. **Apply filters**: Merge user filters with app filters 4. **Generate SQL**: Create optimized query 5. **Apply RLS**: Wrap query with row-level security 6. **Check cache**: Look for cached results (optional) Query executes against your database: ```sql theme={"dark"} -- Example generated query WITH rls_orders AS ( SELECT * FROM orders WHERE customer_id = 'customer-123' AND created_at >= CURRENT_DATE - INTERVAL '30 days' ) SELECT DATE_TRUNC('day', created_at) as date, SUM(amount) as revenue FROM rls_orders GROUP BY date ORDER BY date; ``` DataBrain generates optimized SQL with proper indexing hints and query planning. DataBrain processes query results: * Format data for visualization * Apply number formatting * Calculate aggregations * Handle null values * Apply currency conversions (if configured) Results streamed to frontend: ```json theme={"dark"} { "data": [ { "date": "2024-01-01", "revenue": 125000 }, { "date": "2024-01-02", "revenue": 132000 } ], "metadata": { "executionTime": 245, "cached": false } } ``` Component renders interactive chart with your theme. ### Performance Optimizations **Reduce database load with intelligent caching:** * **Time-based caching**: Cache results for configurable TTL (default: 24 hours) * **Per-tenant caching**: Cache keys include query hash, datasource ID, filters, and workspace ID — ensuring tenant isolation * **Two caching modes**: Use DataBrain's managed Redis or bring your own Redis/Elasticache * **Graceful degradation**: Cache failures never block queries — DataBrain falls back to direct database execution Configure caching in **Workspace Settings → Cache Settings**. Each workspace can independently choose its caching mode and TTL. Complete guide to configuring query caching **Efficient database connection management:** * Connection pool per datasource * Automatic connection recycling * Configurable pool size * Connection health checks * Query timeout management Recommended pool configuration: | Workload | Min Connections | Max Connections | | -------- | --------------- | --------------- | | Light | 2 | 10 | | Medium | 5 | 25 | | Heavy | 10 | 50 | **Automatic query optimization:** ✅ Push-down filters to database\ ✅ Minimize data transfer\ ✅ Use appropriate indexes\ ✅ Parallel query execution\ ✅ Result streaming for large datasets\ ✅ Automatic query planning **Fast-loading embedded components:** * Lazy loading of visualizations * Progressive rendering * Debounced filter updates * Virtual scrolling for tables * Compressed data transfer * CDN delivery of assets *** ## Advanced Architecture Patterns ### Proxy Mode Architecture For enhanced security, route all requests through your own proxy server: **Benefits of proxy mode:** * Guest tokens never exposed to frontend * Additional authentication layer * Request/response modification * Custom logging and monitoring * API rate limiting * Request validation Complete guide to implementing proxy authentication ### Multi-Datasource Architecture Support customers with data in different databases: ```json theme={"dark"} { "clientId": "enterprise-customer", "datasourceName": "customer-dedicated-db", "dataAppName": "analytics" } ``` **Use cases:** * Dedicated database per enterprise customer * Multi-region data residency * Database sharding strategies * Read replica routing Configure multi-datasource workspaces ### High-Availability Architecture Deploy DataBrain with redundancy and failover: **Horizontal scaling with load balancers:** ``` [Load Balancer] | ┌────┼────┬────┐ │ │ │ │ App App App App │ │ │ │ └────┴────┴────┘ | [Database Pool] ``` * Multiple application servers * Session affinity (sticky sessions) * Health check endpoints * Automatic failover **High availability for databases:** * Primary-replica setup * Read replicas for analytics * Automatic failover * Cross-region replication * Point-in-time recovery **Redis for query result caching:** * Use DataBrain's managed Redis or bring your own (BYOC) * Per-workspace cache configuration * Configurable TTL per workspace * Graceful degradation on cache failures Configure caching for your workspace *** ## Deployment Considerations ### Cloud vs Self-Hosted Comparison **Best for:** * Fast time-to-market * Minimal DevOps resources * Automatic updates and maintenance * Built-in scalability * Lower initial investment **Considerations:** * Data passes through DataBrain infrastructure * Requires internet connectivity * Less customization options * Monthly/annual subscription pricing **Best for:** * Strict data sovereignty requirements * Air-gapped environments * Complete infrastructure control * Custom compliance needs * High-volume workloads **Considerations:** * Requires infrastructure management * DevOps/IT resources needed * Responsible for updates and scaling * Higher initial setup cost * One-time license + infrastructure costs ### Self-Hosted Deployment **Required components:** * DataBrain Application Server (Node.js) * PostgreSQL Database (metadata storage) * Redis Cache (session & query caching) * Web UI (admin interface) Deployment instructions and installation packages are provided in your self-hosted license package. **Connect to your databases:** * Private network connections within VPC * Connection pooling configuration * SSL/TLS certificate setup * Read replica configuration (optional) **Configure required environment variables:** ```bash theme={"dark"} # Database DB_HOST=your-postgres-host DB_PORT=5432 DB_NAME=databrain DB_USER=databrain_user DB_PASSWORD=secure_password # Redis (query result caching) REDIS_HOST=your-redis-host REDIS_PORT=6379 REDIS_PASSWORD=your-redis-password # Application NODE_ENV=production PORT=3000 API_BASE_URL=https://your-databrain.company.com ``` **Set up HTTPS for production:** * Obtain SSL certificates * Configure reverse proxy (nginx/Apache) * Enable HTTPS enforcement * Set up certificate auto-renewal **Launch DataBrain platform:** Refer to your self-hosted package for specific deployment commands based on your infrastructure (Docker, Kubernetes, VMs). ### Infrastructure Sizing Guide **Estimate your resource requirements:** | Users (Concurrent) | CPU | Memory | Storage | Bandwidth | | ------------------ | -------------------------------------- | ------ | ------- | --------- | | 1-50 | 2 vCPU | 4 GB | 20 GB | 100 Mbps | | 50-200 | 4 vCPU | 8 GB | 50 GB | 500 Mbps | | 200-500 | 8 vCPU | 16 GB | 100 GB | 1 Gbps | | 500-1000 | 16 vCPU | 32 GB | 200 GB | 2 Gbps | | 1000+ | Contact us for enterprise architecture | | | | **Sizing factors to consider:** * Dashboard complexity (number of metrics) * Query complexity and execution time * Cache hit rate * Number of dashboards per user * Refresh rate requirements *** ## Monitoring & Observability ### Key Metrics to Monitor * Request rate and latency * Error rates and types * Token validation success rate * API endpoint performance * Query execution time * Connection pool utilization * Cache hit/miss ratio * Failed query rate * Concurrent users * Dashboard load times * User session duration * Feature usage patterns * CPU and memory utilization * Network throughput * Disk I/O and space * Container/pod health ### Health Check Endpoints DataBrain provides health check endpoints for liveness and readiness (including Hasura, Keycloak, and Postgres). See [Health Check APIs](/developer-docs/helpers/api-reference/health-check) for full details. ```bash theme={"dark"} # Liveness (process is up) GET /health/live Response: { "status": "live" } # Readiness (backend + Hasura, Keycloak, Postgres) GET /health/ready Response: { "status": "ready"|"not_ready", "checks": { "hasura", "keycloak?", "postgres" } } ``` ### Recommended Monitoring Stack **Tools:** * **DataDog / New Relic**: Full-stack APM * **Prometheus + Grafana**: Open-source metrics * **CloudWatch**: AWS native monitoring **Key dashboards:** * API response times * Error rate tracking * Token generation rate * Active sessions **Tools:** * **pgAdmin / DBeaver**: PostgreSQL monitoring * **Redis Commander**: Redis monitoring * **Database-specific tools**: CloudSQL, RDS monitoring **Key metrics:** * Query performance * Connection counts * Cache efficiency * Slow query log **Tools:** * **Kubernetes Dashboard**: K8s clusters * **AWS CloudWatch**: AWS infrastructure * **Grafana**: Cross-platform visualization **Key alerts:** * High CPU/memory usage * Disk space warnings * Network anomalies * Container restarts **Tools:** * **ELK Stack**: Elasticsearch, Logstash, Kibana * **Splunk**: Enterprise log management * **CloudWatch Logs**: AWS logging **Log categories:** * Application logs * Access logs * Error logs * Audit logs *** ## Troubleshooting & Debugging ### Common Issues **Symptoms:** * "UNAUTHORIZED" errors * "TOKEN\_EXPIRED" messages * "UNAUTHORIZED\_ORIGIN" errors **Solutions:** * Verify API key is correct and active * Check token expiration time * Ensure domain is whitelisted * Verify token is being sent correctly * Check for clock skew between systems **Symptoms:** * Dashboards loading slowly * Timeouts on complex queries * High database load **Solutions:** * Enable query caching * Add database indexes * Optimize RLS rules * Increase connection pool size * Use read replicas for analytics * Review query execution plans **Symptoms:** * "Too many connections" errors * Intermittent connection failures * Slow response times **Solutions:** * Increase max connections in pool config * Reduce connection idle timeout * Scale application horizontally * Optimize query execution time * Check for connection leaks **Symptoms:** * Stale data displayed * Inconsistent results * Memory warnings **Solutions:** * Reduce cache TTL * Clear cache manually if needed * Increase Redis memory * Review cache invalidation logic * Check cache hit rate ### Debug Mode Enable debug logging for troubleshooting: ```javascript theme={"dark"} // Frontend debugging window.dbn = { debug: true, logLevel: 'verbose' }; ``` This will log: * Component lifecycle events * API requests and responses * Token validation steps * Error details *** ## Next Steps Complete step-by-step production deployment guide Comprehensive security and compliance documentation Implement row-level security for multi-tenant apps Complete API documentation for token generation Advanced proxy mode implementation Self-hosted deployment configuration *** ## Additional Resources **Q: How are queries optimized?**\ A: DataBrain applies push-down filters, uses connection pooling, generates indexed queries, and caches results based on your configuration. **Q: What database permissions are required?**\ A: DataBrain only needs SELECT permissions on the tables you want to query. No write access is required. **Q: How is high availability achieved?**\ A: Cloud deployments have built-in HA. Self-hosted can deploy with load balancers, multiple app servers, and database replicas. **Q: Can I customize query generation?**\ A: While DataBrain optimizes queries automatically, you can control them through metric definitions and filter configurations. **Q: What's the token refresh strategy?**\ A: Generate new tokens before expiration (e.g., when token has 10% life remaining). Your backend should handle this automatically. **Application Level:** * Enable query caching with appropriate TTL * Use connection pooling (adjust based on load) * Implement CDN for static assets * Enable compression for API responses **Database Level:** * Create indexes on filtered columns * Use read replicas for analytics workload * Optimize RLS queries for performance * Monitor slow query log **Infrastructure Level:** * Scale horizontally with load balancing * Use Redis cluster for caching layer * Deploy close to your database (reduce latency) * Implement proper monitoring and alerting DataBrain maintains industry-leading security certifications: * **SOC 2 Type II**: Annual audits of security controls * **ISO 27001**: Information security management * **GDPR**: European data protection compliance * **HIPAA**: Healthcare data protection (self-hosted) * **PCI DSS**: Payment card data security [View Security Page →](https://www.usedatabrain.com/security) **Need technical support?** * 📚 Documentation: [docs.usedatabrain.com](https://docs.usedatabrain.com) * 💬 Contact support through your DataBrain dashboard **Enterprise customers:** Contact your dedicated solutions architect for architecture reviews and optimization guidance. # Production-Ready Embedding Guide Source: https://docs.usedatabrain.com/developer-docs/embedding-setup/step-by-step-guide Complete step-by-step guide to embedding DataBrain dashboards in production This guide walks you through everything you need to embed DataBrain dashboards in a production environment with proper authentication, security, and customization. ## What You'll Build By the end of this guide, you'll have: * ✅ A secure backend endpoint that generates guest tokens * ✅ A frontend application with embedded DataBrain dashboards * ✅ Row-level security for multi-tenant access control (optional) * ✅ Customized dashboard appearance matching your brand * ✅ Production-ready authentication flow **Requirements:** Basic knowledge of REST APIs, frontend frameworks, and environment variables ## Quick Navigation Jump to any section: * [Prerequisites](#prerequisites) * [Architecture Overview](#architecture-overview) * [Step 1: Create Workspace & Dashboard](#step-1-create-workspace--dashboard) * [Step 2: Create Data App](#step-2-create-data-app) * [Step 3: Backend Integration](#step-3-backend-integration) * [Step 4: Frontend Integration](#step-4-frontend-integration) * [Step 5: Testing & Deployment](#step-5-testing--deployment) * [Next Steps](#next-steps) ## Prerequisites Ensure you have the following before starting: | Requirement | Description | Link | | --------------------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------- | | **DataBrain Account** | Sign up for a free account | [app.usedatabrain.com](https://app.usedatabrain.com/users/sign-up) | | **Data Source** | Connected database or data warehouse | [Data Sources Guide](/guides/onboarding-and-configuration/add-a-data-source) | | **Backend Server** | For secure token generation (Node.js, Python, Go, .NET, etc.) | - | | **Frontend App** | React, Vue, Angular, or vanilla JS application | - | ## Architecture Overview **Flow Diagram:** Create Architecture Diagram Pn
Understanding the Architecture (Optional Reading) Here's how the embedding architecture works: End user logs into your application Your frontend requests a guest token from your backend Your backend calls DataBrain API to generate a guest token ```bash theme={"dark"} POST https://api.usedatabrain.com/api/v2/guest-token/create ``` DataBrain API returns guest token to your backend, which passes it to frontend Frontend passes token to the dbn-dashboard web component ```html theme={"dark"} ``` Component fetches dashboard data from DataBrain using the guest token Dashboard renders with user-specific data and permissions
## Step 1: Create Workspace & Dashboard ### 1.1 Create a Workspace Go to the DataBrain platform and click "Create Workspace" * Enter workspace name * Select workspace type (standard or private) * Configure initial settings Detailed workspace creation guide ### 1.2 Connect Data Source Click "Add Data Source" in your workspace Choose from 18+ supported databases Provide connection details (host, port, credentials) Verify the connection works Set up multi-tenancy if needed Connect your database ### 1.3 Create Dashboard Click "New Dashboard" in your workspace Create charts, tables, and KPIs using the visual builder Configure dashboard-level filters for interactivity Arrange metrics and adjust sizing Save and note your dashboard ID Build your first dashboard **Step 1 Complete!** Before moving to Step 2, verify you have: * Created a workspace in DataBrain * Successfully connected at least one data source * Built and saved a dashboard with metrics * Noted your dashboard ID for later use ## Step 2: Create Data App A Data App packages your dashboards for embedding with security and configuration. ### 2.1 Navigate to Data Apps Go to **Data → Data Apps** in your workspace ### 2.2 Create New Data App Start creating a new Data App ```json theme={"dark"} { "name": "customer-analytics-app", "description": "Analytics for customer portal", "workspace": "your-workspace-name" } ``` * Choose the dashboards you want to expose through the Data App for embedding. * Browse and select one or more dashboards from your workspace. * Only selected dashboards can be accessed via guest tokens. * Save the Data App to generate and use their embed IDs in embedding. * **Tip:** Add only relevant dashboards to keep access secure and organized. * Set default permissions * Configure multi-tenancy * Set token expiry defaults Copy your API token - you'll need this for generating guest tokens **Store your API token securely!** Never commit it to version control or expose it in frontend code. Use environment variables. ### 2.3 Find Your Dashboard ID Navigate to your Data App Look for the dashboards list Each dashboard has a unique ID (e.g., `sales-dashboard-2024`) Detailed guide on locating IDs **Step 2 Complete!** Before moving to Step 3, verify you have: * Created a Data App in your workspace * Added your dashboard(s) to the Data App * Copied and securely stored your API token * Have your Data App name ready (e.g., `customer-analytics-app`) ## Step 3: Backend Integration Set up your backend to generate guest tokens securely. ### 3.1 Store API Token Add your DataBrain API token to environment variables: ```bash .env theme={"dark"} DATABRAIN_API_TOKEN=dbn_live_abc123... DATABRAIN_API_URL=https://api.usedatabrain.com DATA_APP_NAME=customer-analytics-app ``` ```yaml docker-compose.yml theme={"dark"} environment: - DATABRAIN_API_TOKEN=dbn_live_abc123... - DATA_APP_NAME=customer-analytics-app ``` ```json Kubernetes ConfigMap theme={"dark"} apiVersion: v1 kind: Secret metadata: name: databrain-secrets type: Opaque stringData: api-token: "dbn_live_abc123..." data-app-name: "customer-analytics-app" ``` ### 3.2 Implement Token Generation Create an API endpoint to generate guest tokens: ```javascript Node.js/Express theme={"dark"} // routes/databrain.js const express = require('express'); const router = express.Router(); router.post('/guest-token', async (req, res) => { try { const { userId } = req.user; // From your auth middleware const response = await fetch( `${process.env.DATABRAIN_API_URL}/api/v2/guest-token/create`, { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.DATABRAIN_API_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: userId, dataAppName: process.env.DATA_APP_NAME, expiryTime: 3600000 // 1 hour }) } ); const data = await response.json(); if (!response.ok) { throw new Error(data.error?.message || 'Failed to generate token'); } res.json({ token: data.token }); } catch (error) { console.error('Token generation error:', error); res.status(500).json({ error: 'Failed to generate token' }); } }); module.exports = router; ``` ```python Python/FastAPI theme={"dark"} from fastapi import APIRouter, HTTPException, Depends from pydantic import BaseModel import httpx import os router = APIRouter() class TokenResponse(BaseModel): token: str @router.post("/guest-token", response_model=TokenResponse) async def get_guest_token(current_user: User = Depends(get_current_user)): try: async with httpx.AsyncClient() as client: response = await client.post( f"{os.getenv('DATABRAIN_API_URL')}/api/v2/guest-token/create", headers={ "Authorization": f"Bearer {os.getenv('DATABRAIN_API_TOKEN')}", "Content-Type": "application/json" }, json={ "clientId": str(current_user.id), "dataAppName": os.getenv('DATA_APP_NAME'), "expiryTime": 3600000 # 1 hour } ) if response.status_code != 200: raise HTTPException(status_code=500, detail="Token generation failed") data = response.json() return TokenResponse(token=data["token"]) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) ``` ```go Go/Gin theme={"dark"} package handlers import ( "bytes" "encoding/json" "net/http" "os" "github.com/gin-gonic/gin" ) type TokenRequest struct { ClientID string `json:"clientId"` DataAppName string `json:"dataAppName"` ExpiryTime int `json:"expiryTime"` } type TokenResponse struct { Token string `json:"token"` } func GetGuestToken(c *gin.Context) { userID := c.GetString("userID") // From auth middleware reqBody := TokenRequest{ ClientID: userID, DataAppName: os.Getenv("DATA_APP_NAME"), ExpiryTime: 3600000, // 1 hour } jsonData, _ := json.Marshal(reqBody) req, _ := http.NewRequest( "POST", os.Getenv("DATABRAIN_API_URL")+"/api/v2/guest-token/create", bytes.NewBuffer(jsonData), ) req.Header.Set("Authorization", "Bearer "+os.Getenv("DATABRAIN_API_TOKEN")) req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { c.JSON(500, gin.H{"error": "Token generation failed"}) return } defer resp.Body.Close() var tokenResp TokenResponse json.NewDecoder(resp.Body).Decode(&tokenResp) c.JSON(200, tokenResp) } ``` ```csharp C#/.NET theme={"dark"} using Microsoft.AspNetCore.Mvc; using System.Net.Http; using System.Text; using System.Text.Json; [ApiController] [Route("api/[controller]")] public class DataBrainController : ControllerBase { private readonly IHttpClientFactory _httpClientFactory; private readonly IConfiguration _configuration; public DataBrainController( IHttpClientFactory httpClientFactory, IConfiguration configuration) { _httpClientFactory = httpClientFactory; _configuration = configuration; } [HttpPost("guest-token")] public async Task GetGuestToken() { var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value; var requestBody = new { clientId = userId, dataAppName = _configuration["DataBrain:AppName"], expiryTime = 3600000 }; var client = _httpClientFactory.CreateClient(); var request = new HttpRequestMessage(HttpMethod.Post, $"{_configuration["DataBrain:ApiUrl"]}/api/v2/guest-token/create"); request.Headers.Add("Authorization", $"Bearer {_configuration["DataBrain:ApiToken"]}"); request.Content = new StringContent( JsonSerializer.Serialize(requestBody), Encoding.UTF8, "application/json"); var response = await client.SendAsync(request); if (!response.IsSuccessStatusCode) { return StatusCode(500, "Token generation failed"); } var result = await response.Content.ReadAsStringAsync(); var tokenData = JsonSerializer.Deserialize(result); return Ok(tokenData); } } ``` #### Verify Token Generation Test your endpoint to ensure tokens are being generated correctly: ```bash cURL theme={"dark"} curl -X POST http://localhost:3000/api/databrain/guest-token \ -H "Authorization: Bearer your-app-auth-token" \ -H "Content-Type: application/json" # Expected Response: # { # "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." # } ``` ```javascript Postman/JavaScript theme={"dark"} // Test in your browser console or Postman fetch('http://localhost:3000/api/databrain/guest-token', { method: 'POST', credentials: 'include' }) .then(res => res.json()) .then(data => console.log('Token:', data.token)) .catch(err => console.error('Error:', err)); ```
Advanced: Add Row-Level Security (Multi-Tenant Apps) ### 3.3 Advanced Token Configuration Add Row-Level Security (RLS) and filters: ```javascript theme={"dark"} // With RLS and app filters const tokenRequest = { clientId: userId, dataAppName: process.env.DATA_APP_NAME, params: { // Row-level security rlsSettings: [{ metricId: 'sales-metric', values: { customer_id: userCustomerId, region: userRegion } }], // Dashboard app filters dashboardAppFilters: [{ dashboardId: 'sales-dashboard', values: { date_range: { startDate: '2024-01-01', endDate: '2024-12-31' }, region: userRegion }, isShowOnUrl: false }] }, // Permissions permissions: { isEnableDownloadMetrics: true, isEnableUnderlyingData: false, isEnableManageMetrics: false }, expiryTime: 3600000 }; ``` Complete token configuration options
**Step 3 Complete!** Before moving to Step 4, verify you have: * Environment variables configured with API token * Backend endpoint created for token generation * Successfully tested token generation (returns valid JWT) * Tokens are secured server-side (never exposed to frontend) ## Step 4: Frontend Integration ### 4.1 Install Package ```bash theme={"dark"} npm install @databrainhq/plugin ``` ### 4.2 Create Dashboard Component
Framework-Specific Integration Guides ```javascript React theme={"dark"} import { useEffect, useState } from 'react'; import '@databrainhq/plugin/web'; function AnalyticsDashboard() { const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { async function fetchToken() { try { const response = await fetch('/api/databrain/guest-token', { method: 'POST', credentials: 'include' // Include auth cookies }); if (!response.ok) { throw new Error('Failed to fetch token'); } const data = await response.json(); setToken(data.token); } catch (err) { setError(err.message); } finally { setLoading(false); } } fetchToken(); }, []); if (loading) { return
Loading dashboard...
; } if (error) { return
Error loading dashboard: {error}
; } return (
); } export default AnalyticsDashboard; ``` ```javascript Vue theme={"dark"} ``` ```typescript TypeScript/Next.js theme={"dark"} import { useEffect, useState } from 'react'; import type { NextPage } from 'next'; import '@databrainhq/plugin/web'; declare global { namespace JSX { interface IntrinsicElements { 'dbn-dashboard': any; } } } const Analytics: NextPage = () => { const [token, setToken] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { async function fetchToken() { try { const response = await fetch('/api/databrain/guest-token', { method: 'POST' }); if (!response.ok) { throw new Error('Token fetch failed'); } const data = await response.json(); setToken(data.token); } catch (err) { setError((err as Error).message); } finally { setLoading(false); } } fetchToken(); }, []); if (loading) return
Loading...
; if (error) return
Error: {error}
; return ( ); }; export default Analytics; ```
**Basic Implementation (All Frameworks):** ```html theme={"dark"} ```
Optional: Customize Dashboard Appearance ### 4.3 Add Customization ```javascript theme={"dark"} ``` All customization options
**Step 4 Complete!** Before moving to Step 5, verify you have: * Installed `@databrainhq/plugin` package * Created a dashboard component in your frontend * Dashboard successfully fetches token from your backend * Dashboard renders with data from DataBrain ## Step 5: Testing & Deployment ### 5.1 Test Locally Ensure your backend token endpoint is running Run your frontend development server Check that the dashboard renders correctly * Click on charts * Apply filters * Download CSV * Test responsive behavior ### 5.2 Environment Variables Set up environment variables for each environment: ```bash Development theme={"dark"} DATABRAIN_API_TOKEN=dbn_test_... DATABRAIN_API_URL=https://api.usedatabrain.com DATA_APP_NAME=my-app-dev ``` ```bash Production theme={"dark"} DATABRAIN_API_TOKEN=dbn_live_... DATABRAIN_API_URL=https://api.usedatabrain.com DATA_APP_NAME=my-app-prod ``` **🎉 Congratulations! You're Production-Ready** Your embedded analytics are now live! You've successfully: * Created DataBrain workspace and dashboards * Set up secure backend token generation * Integrated dashboard into your frontend * Deployed to production **What's next?** Explore multi-tenancy, SSO, and advanced customization below. ## Next Steps Implement row-level security Set up single sign-on Deep dive into options Common implementation patterns # Introduction Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide This article will guide you integrate databrain plugin in your respective UI framework/libraries. # Angular Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/angular ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link View the complete Angular integration example on GitHub ## Usage Add support for custom elements/web components in `app.module.ts` ```ts theme={"dark"} // app.module.ts import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; // server event (window as any).databrainServerEvent = (error: any) => { console.log(error); }; @NgModule({ declarations: [AppComponent], imports: [BrowserModule], providers: [], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class AppModule {} ``` ### Import in `app.component.ts` ```ts theme={"dark"} import '@databrainhq/plugin/web'; ``` ### Then use it anywhere in your app #### Integrating Dashboard ```html theme={"dark"} ``` #### Integrating Metric ```html theme={"dark"} ``` customMessages - In your parent component, assign the `customMessages` prop like this: ```ts theme={"dark"} this.customMessages = { tokenExpiry: "Some custom message you want to show here." }; ``` metricFilterOptions - In your parent component, assign the `metricFilterOptions` prop like this: ```ts theme={"dark"} this.metricFilterOptions = { // note that invalid options will be filtered out "Filter name for a string datatype": { options: ['hello', 'hi'], // should have unique elements defaultOption: 'hello', // name of the option }, "Filter name for a number datatype": { options: [9, 19, 23], // should have unique elements defaultOption: 19, // name of the option }, "Filter name for a date datatype": { options: [{ range: 'Last|This|Custom', // one of the three option time: 'Day|Week|Month|Quarter|Year', // one of the five option ignored for range = "Custom" name: 'Last 10 Years', // will be shown in the list count: 10, // required for range = "Last" else ignored fromDate: new Date(), // optional if you don't want date picker for custom range else ignored toDate: new Date(), // optional if you don't want date picker for custom range else ignored minDate: new Date(), // optional for custom range else ignored maxDate: new Date(), // optional for custom range else ignored },{ range: 'Last|This|Custom', // one of the three option time: 'Day|Week|Month|Quarter|Year', // one of the five option for range "Custom" nit required name: 'This Year', // will be shown in the list count: 0, // required for range "Last" else not required minDate: new Date(), // optional for custom range maxDate: new Date(), // optional for custom range }], defaultOption: 'Last 10 Years', // name of the option }, } ``` appearanceOptions - In your parent component, assign the `appearanceOptions` prop like this: ```ts theme={"dark"} this.appearanceOptions = { appearanceOptionsPosition: 'top-left|top-right|bottom-left|bottom-right', // one of the four options, by default it is bottom-right cumulativeBar: { isEnabled: true|false, // can be used with bar and time series charts (if series type is bar) label: 'Cumulative' // change the label for the property }, stackedBars: { isEnabled: true|false, // can be used with stack chart only label: '100% stacked bars', // change the label for the property }, dynamicBehaviour: { isEnabled: true|false, // can be used with bar, line, area, stacked area and time series charts label: 'Dynamic' //change the label for the property }, } ``` # Nextjs Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/nextjs ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link View the complete Next.js integration example on GitHub ## Usage ### Quick usage: ```tsx theme={"dark"} "use client"; import '@databrainhq/plugin/web'; export default function Home() { const url = new URL(location.href); const token = url.searchParams.get("token"); const dashboardId = url.searchParams.get("dashboardId"); return (
); } declare global { namespace JSX { interface IntrinsicElements { "dbn-dashboard": any; "dbn-metric": any; } } } ``` For embedding a Metric Card you can use the `dbn-metric` webcomponent: ```html theme={"dark"} ``` * To find dashboardId please see here. * To find metricId please see here. ## Token The [`token`](https://docs.usedatabrain.com/developer-docs/token) should be a guest token, fetched from your backend based on the current user's login information. You can see more [about it here](https://docs.usedatabrain.com/developer-docs/token). Here is an example with sample token and dashboardId that you can use in your frontend app to get started without a backend. ```html theme={"dark"} ``` ### **Breakdown:** Import the library main or index or App or layout file ```js theme={"dark"} import '@databrainhq/plugin/web'; ``` Once the library is imported, the web-components `dbn-dashboard`, `dbn-metrics` are available to use anywhere inside your app. And you can use it anywhere in your app like: ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` ## Integrating metric ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` To see the full list of options please check the [options list](https://docs.usedatabrain.com/developer-docs/helpers/options). # Reactjs Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/reactjs ## @databrainhq/plugin > Databrain app UI web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. To see the full list of options please check the [options list](https://docs.usedatabrain.com/developer-docs/helpers/options). ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link View the complete React integration example on GitHub ## Usage **Quick usage:** ```tsx showLineNumbers title="App.tsx" theme={"dark"} // React + Databrain plugin example import React, { useState, useEffect } from 'react'; import '@databrainhq/plugin/web'; import './App.css'; declare global { namespace JSX { interface IntrinsicElements { 'dbn-dashboard': any; 'dbn-metric': any; } } } function App() { const [token, setToken] = useState(null); const dashboardId = 'your-dashboard-id'; // Replace with your actual dashboard ID useEffect(() => { const fetchToken = async () => { try { const response = await fetch('/fetch-guest-token'); if (!response.ok) { throw new Error('Failed to fetch token'); } const data = await response.json(); setToken(data.token); // Assuming the API returns the token in a 'token' field } catch (error) { console.error('Error fetching token:', error); } }; fetchToken(); }, []); if (!token) { return
Loading...
; } return ( ); } export default App; ``` For embedding a Metric Card you can use the `dbn-metric` webcomponent: ```html theme={"dark"} ``` ### Token The [`token`](https://docs.usedatabrain.com/developer-docs/helpers/token-body) should be a guest token, fetched from your backend based on the current user's login information. You can follow the document below for guest token generation. Here is an example with sample token and dashboardId that you can use in your frontend app to get started without a backend. ```html theme={"dark"} ``` #### Breakdown: Import the library main or index or App or layout file ```ts theme={"dark"} import '@databrainhq/plugin/web'; ``` Once the library is imported, the web-components `dbn-dashboard`, `dbn-metrics` are available to use anywhere inside your app. And you can use it anywhere in your app like: ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` ## Intgerating Metric ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` # Solid Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/solid ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link View the complete Solid.js integration example on GitHub ## Usage Import in main/index/App ```ts theme={"dark"} import '@databrainhq/plugin/web'; ``` Then use it anywhere in your app ## Integrating Dashboard: ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` ## Integrating Metric ```tsx theme={"dark"} const Example = () => { return ( ); }; ``` # Svelte Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/svelte ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link View the complete Svelte integration example on GitHub ## Usage Import in main/index/App ```svelte theme={"dark"} ``` ### Integrating Dashboard ```svelte theme={"dark"}
``` ### Integrating Metric ```svelte theme={"dark"}
``` # Vanilla JS Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/vanillajs ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Github Repo Link [https://github.com/databrainhq/dbn-demos-updated/tree/main/dbn-demo-vanilla](https://github.com/databrainhq/dbn-demos-updated/tree/main/dbn-demo-vanilla) ## Usage In your index.html file, add the following script ```html theme={"dark"} ``` **Note:** If you want to use a specific version, add the version in place of latest. For example ```html theme={"dark"} ``` **If you get process error in your console, add the below script above your cdn script** ```html theme={"dark"} ``` Use global document object to create components. Add the below script in your script file like main.js or inside script tags. ### Integrating Dashboard: ```js theme={"dark"} function initDashboard() { const url = new URL(location.href); const token = url.searchParams.get("token") || ""; const dashboardId = url.searchParams.get("dashboardId") || ""; // Create the dashboard element const dashboardElement = document.createElement('dbn-dashboard'); // Set attributes if (token) { dashboardElement.setAttribute('token', token); } if (dashboardId) { dashboardElement.setAttribute('dashboard-id', dashboardId); } // Append the dashboard to the body document.body.appendChild(dashboardElement); } // Initialize the dashboard when the DOM is fully loaded document.addEventListener('DOMContentLoaded', initDashboard); ``` ### Integrating Metric ```js theme={"dark"} function initMetric() { const url = new URL(location.href); const token = url.searchParams.get("token") || ""; const dashboardId = url.searchParams.get("metricId") || ""; // Create the metric element const metricElement = document.createElement('dbn-metric'); // Set attributes if (token) { metricElement.setAttribute('token', token); } if (dashboardId) { metricElement.setAttribute('metric-id', dashboardId); } // Append the metric to the body document.body.appendChild(metricElement); } // Initialize the metric when the DOM is fully loaded document.addEventListener('DOMContentLoaded', initMetric); ``` **Note:** If you don't want to use cdn link, you can install the below npm package. ```bash theme={"dark"} npm i @databrainhq/plugin ``` Add import statement like below in your main.js file. ```js theme={"dark"} import "@databrainhq/plugin/web"; ``` # Vuejs Source: https://docs.usedatabrain.com/developer-docs/framework-specific-guide/vuejs ## @databrainhq/plugin > Databrain app ui web component plugin. v0.15.135-uat Enforced using StandardJS styleguide. ## Install ```bash theme={"dark"} npm install @databrainhq/plugin ``` ## Github Repo Link [https://github.com/databrainhq/dbn-demos-updated/tree/main/dbn-demo-vue](https://github.com/databrainhq/dbn-demos-updated/tree/main/dbn-demo-vue) ## Usage Import in `App/main/index.(vue/ts/js)`: ```ts theme={"dark"} import '@databrainhq/plugin/web'; ``` ### Integrating Dashboard ```html theme={"dark"} ``` ### Integrating metric ```html theme={"dark"} ``` # Admin Authentication Flow Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/admin-authentication-flow Understand the complete flow for setting up and managing admin authentication on self-hosted Databrain instances. This guide walks you through the complete authentication flow for self-hosted Databrain instances. Follow these steps in order to set up your admin account and service tokens. **Self-Hosted Only:** All endpoints described in this flow are available only on **self-hosted** Databrain instances. They will return errors on cloud (SaaS) deployments. ## Step-by-Step Process If this is your first time setting up your self-hosted instance, create the initial admin account using the [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account) endpoint. **What you need:** * Admin first name * Admin email address * Secure password (meets complexity requirements) * Company name **What you get:** * An `accessToken` (JWT) that you can use for subsequent admin operations This step is only needed once. If an admin account already exists, proceed to step 2. For existing admin accounts, sign in using the [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) endpoint to receive an access token. **What you need:** * Admin email address * Admin password **What you get:** * An `accessToken` (JWT) for authenticated admin operations Use this token in the `Authorization: Bearer ` header for admin-only endpoints. Once you have an admin access token, create a service token using the [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) endpoint. **What you need:** * Admin `accessToken` from step 1 or 2 (in Authorization header) * A UUID value for the service token **What you get:** * A `serviceToken` (UUID) that can be used for organization-level operations such as: * Creating Data App API tokens * Managing Data Apps * Export/import operations Generate a UUID using your preferred method (e.g., `uuidv4()` in Node.js, `uuid.uuid4()` in Python). Store this token securely as it provides elevated permissions. Periodically rotate your service token for enhanced security using the [Rotate Service Token](/developer-docs/helpers/api-reference/rotate-service-token) endpoint. **What you need:** * Admin `accessToken` (in Authorization header) * Current service token UUID * Expiration grace period (in seconds) **What you get:** * A new `serviceToken` UUID * The old token expires after the grace period Use a grace period (e.g., 3600 seconds = 1 hour) to allow time for updating clients before the old token stops working. Change your admin password using the [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password) endpoint. **What you need:** * Admin `accessToken` (in Authorization header) * Current password * New password (meets complexity requirements) **What you get:** * Confirmation that the password was changed successfully After resetting your password, you'll need to sign in again using Create Admin JWT to get a new access token. ## Common Scenarios **Complete flow for new installations:** 1. Create Admin Account → Get `accessToken` 2. Create Service Token → Get `serviceToken` 3. Use `serviceToken` for organization operations This is a one-time setup process. **For existing admin accounts:** 1. Create Admin JWT → Get `accessToken` 2. Use `accessToken` for admin operations 3. Create or rotate service tokens as needed Repeat this whenever you need to perform admin operations. **For security best practices:** 1. Create Admin JWT → Get `accessToken` 2. Rotate Service Token → Get new `serviceToken` 3. Update all clients with new `serviceToken` 4. Old token expires after grace period Rotate tokens periodically (recommended: every 6 months). **When you need to change your password:** 1. Create Admin JWT → Get `accessToken` 2. Reset Admin Password → Confirm change 3. Create Admin JWT again → Get new `accessToken` After password reset, your old access tokens may become invalid. ## Security Best Practices * Never commit tokens to version control * Use environment variables or secrets managers * Rotate tokens regularly * Minimum 8 characters * Mix of uppercase, lowercase, digits, and special characters * No spaces * Rotate service tokens every 6 months * Use grace periods during rotation * Update all clients before expiration * Track token usage * Revoke compromised tokens immediately * Use separate tokens for different environments ## Related Documentation * [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account) – Create the first admin account * [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) – Sign in and get access token * [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) – Create organization service token * [Rotate Service Token](/developer-docs/helpers/api-reference/rotate-service-token) – Rotate service token securely * [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password) – Change admin password # Fetch Dashboards by Workspace Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/cloud-databrain-endpoint POST https://api.usedatabrain.com/api/v2/workspace/dashboards Retrieve a list of dashboards available in a workspace with optional pagination support. Retrieve a list of dashboards available in a workspace. Use this endpoint to discover dashboards for provisioning and embedding in your application. This endpoint operates at the workspace level using a service token. Use the workspace name to scope which dashboards are returned. Supports pagination for workspaces with many dashboards. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the workspace to fetch dashboards from. Must match an existing workspace in your organization. * Use the [List Workspaces](/developer-docs/helpers/api-reference/list-workspaces) endpoint to see all available workspaces * Names are case-sensitive * Must be an exact match Enable pagination to retrieve dashboards in batches of 10. * `true`: Enable pagination with page-based retrieval (10 items per page) * `false` (default): Return all dashboards in a single response - Use pagination when you have more than 20 dashboards in a workspace - Improves response times for large datasets - Each page returns up to 10 dashboards The page number to retrieve when pagination is enabled. Pages are 1-indexed. **Note:** This parameter is only used when `isPagination` is set to `true`. ## Response Array of dashboard objects. Returns empty array if no dashboards exist or page number exceeds available pages. Display name of the dashboard. Unique identifier for the dashboard. Error object if the request failed, otherwise `null` for successful requests. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - All Dashboards theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "my-workspace" }' ``` ```bash cURL - With Pagination theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "my-workspace", "isPagination": true, "pageNumber": 1 }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace/dashboards', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ workspaceName: 'my-workspace', isPagination: true, pageNumber: 1 }) }); const result = await response.json(); console.log('Dashboards:', result.data); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/workspace/dashboards', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'workspaceName': 'my-workspace', 'isPagination': True, 'pageNumber': 1 } ) result = response.json() print(f"Dashboards: {result['data']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/workspace/dashboards') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { workspaceName: 'my-workspace', isPagination: true, pageNumber: 1 }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Dashboards: #{result['data']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class FetchDashboards { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "workspaceName": "my-workspace", "isPagination": true, "pageNumber": 1 } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/workspace/dashboards")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) type DashboardRequest struct { WorkspaceName string `json:"workspaceName"` IsPagination bool `json:"isPagination,omitempty"` PageNumber int `json:"pageNumber,omitempty"` } func main() { reqData := DashboardRequest{ WorkspaceName: "my-workspace", IsPagination: true, PageNumber: 1, } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/workspace/dashboards", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'my-workspace', 'isPagination' => true, 'pageNumber' => 1 ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); print_r($result['data']); ?> ``` ```json 200 - Success theme={"dark"} { "data": [ { "name": "Sales Dashboard", "externalDashboardId": "sales_dash_123" }, { "name": "Marketing Analytics", "externalDashboardId": "marketing_dash_456" } ], "error": null } ``` ```json 200 - Empty Results theme={"dark"} { "data": [], "error": null } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"workspaceName\" is required" } } ``` ```json 400 - Workspace Not Found theme={"dark"} { "error": { "code": "WORKSPACE_ID_ERROR", "message": "The workspace name provided does not exist" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "API Key is not provided or Invalid!" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Dashboards retrieved successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------ | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid request body parameters | | `WORKSPACE_ID_ERROR` | 400 | Workspace name does not exist | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid or expired API key | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Next Steps Retrieve metrics from a workspace List all workspaces in your organization Create a new workspace for your analytics environment Generate secure tokens for embedded access # Create Admin Account (Self-Hosted) Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-admin-account POST https://api.usedatabrain.com/api/v2/admin-account Create the first admin account for your self-hosted Databrain instance. Returns an access token for the new admin. Self-hosted only. Create the initial admin user and company for a self-hosted deployment. On success, the API returns an access token that can be used for subsequent admin operations (e.g. creating a service token, managing Data Apps). Only one company can exist on a self-hosted instance; if an account already exists, sign in via [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) instead. **Self-Hosted Only:** This endpoint is available only on **self-hosted** Databrain instances. Calling it on cloud will return an error. ## Headers Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body Admin user's first name. Must be between **3 and 30 characters**. Admin user's email address. Must be a valid email with at least two domain segments (e.g. `user@example.com`). Some common consumer email domains may be blocked (e.g. gmail, yahoo, outlook). Password for the admin account. Must meet: * Minimum **8 characters** * At least **1 uppercase** letter * At least **1 lowercase** letter * At least **1 digit** * At least **1 special character** * **No spaces** Name of the company/organization to create for this admin. ## Response On success, the API returns **200** with a JSON object: Wrapper object for the response payload. JWT access token for the newly created admin. Use this in the `Authorization: Bearer ` header for admin APIs (e.g. [Create Service Token](/developer-docs/helpers/api-reference/create-service-token), [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password)). On error, the API returns a JSON object with `error.code` and `error.message` and an appropriate HTTP status (400 or 500). ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/admin-account \ --header 'Content-Type: application/json' \ --data '{ "firstName": "Admin", "email": "admin@company.com", "password": "SecureP@ss1", "companyName": "My Company" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/admin-account', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ firstName: 'Admin', email: 'admin@company.com', password: 'SecureP@ss1', companyName: 'My Company' }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); const accessToken = data.data.accessToken; ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/admin-account" headers = {"Content-Type": "application/json"} payload = { "firstName": "Admin", "email": "admin@company.com", "password": "SecureP@ss1", "companyName": "My Company" } response = requests.post(url, headers=headers, json=payload) data = response.json() if data.get("error"): raise Exception(data["error"].get("message", "Request failed")) access_token = data["data"]["accessToken"] ``` ```json Success (200) theme={"dark"} { "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` ```json Error (400) - Validation (Joi) theme={"dark"} { "error": { "code": "INVALID REQUEST BODY", "message": "\"firstName\" is required" } } ``` ```json Error (400) - Company already exists (self-hosted) theme={"dark"} { "error": { "code": "INVALID_REQUEST", "message": "Your company account is already created, please sign in" } } ``` ```json Error (500) theme={"dark"} { "error": { "code": "SELFHOSTED_APP_ERROR", "message": "This feature is only available for self-hosted instances" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ----------------------------------------------------------------------------------------------------------- | | `200` | **OK** – Admin account created; `data.accessToken` returned | | `400` | **Bad Request** – Validation error (invalid email, weak password, missing fields) or company already exists | | `500` | **Internal Server Error** – Server error or self-hosted-only error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------- | | `INVALID REQUEST BODY` | Joi validation message (e.g. `"firstName" is required`, `"password" should contain at least 1 uppercase character`) | 400 | | `INVALID_REQUEST` | Your company account is already created, please sign in | 400 | | `SELFHOSTED_APP_ERROR` | This feature is only available for self-hosted instances | 500 | | `INTERNAL_SERVER_ERROR` | INTERNAL\_SERVER\_ERROR | 500 | ## Related * [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) – Sign in and get an access token for an existing admin * [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) – Create a service token using the admin access token * [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password) – Change password for the authenticated admin # Create Admin JWT (Self-Hosted) Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-admin-jwt POST https://api.usedatabrain.com/api/v2/admin-account/jwt Sign in as an admin and receive a JWT access token for self-hosted Databrain. Use this token for service token and admin APIs. Self-hosted only. Sign in with an existing admin email and password to receive a JWT access token. Use this token in the `Authorization` header when calling admin-only endpoints such as [Create Service Token](/developer-docs/helpers/api-reference/create-service-token), [Rotate Service Token](/developer-docs/helpers/api-reference/rotate-service-token), and [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password). **Self-Hosted Only:** This endpoint is available only on **self-hosted** Databrain instances. ## Headers Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body Admin user's email address. Must be a valid email with at least two domain segments. Admin user's password. ## Response On success, the API returns **200** with a JSON object: Wrapper object for the response payload. JWT access token. Use as `Authorization: Bearer ` for admin and service-token APIs. On error, the API returns a JSON object with `error.code` and `error.message` and an appropriate HTTP status (400 or 500). ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/admin-account/jwt \ --header 'Content-Type: application/json' \ --data '{"email":"admin@company.com","password":"SecureP@ss1"}' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/admin-account/jwt', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: 'admin@company.com', password: 'SecureP@ss1' }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); const accessToken = data.data.accessToken; ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/admin-account/jwt" headers = {"Content-Type": "application/json"} payload = { "email": "admin@company.com", "password": "SecureP@ss1" } response = requests.post(url, headers=headers, json=payload) data = response.json() if data.get("error"): raise Exception(data["error"].get("message", "Request failed")) access_token = data["data"]["accessToken"] ``` ```json Success (200) theme={"dark"} { "data": { "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } } ``` ```json Error (400) - Wrong password theme={"dark"} { "error": { "code": "Invalid credentials", "message": "Invalid credentials" } } ``` ```json Error (400) - User not found theme={"dark"} { "error": { "code": "USER_NOT_FOUND", "message": "No User found with the given email" } } ``` ```json Error (500) theme={"dark"} { "error": { "code": "SELFHOSTED_APP_ERROR", "message": "This feature is only available for self-hosted instances" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------ | | `200` | **OK** – Access token returned in `data.accessToken` | | `400` | **Bad Request** – Invalid credentials or validation error | | `500` | **Internal Server Error** – Server error or self-hosted-only error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | --------------------------------------------------------------- | ----------- | | `USER_NOT_FOUND` | No User found with the given email | 400 | | `Invalid credentials` | Invalid credentials (when password is incorrect or login fails) | 400 | | `SELFHOSTED_APP_ERROR` | This feature is only available for self-hosted instances | 500 | | `INTERNAL SERVER ERROR` | Connection Failure | 500 | ## Related * [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account) – Create the first admin account * [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) – Create a service token (requires this JWT) * [Reset Admin Password](/developer-docs/helpers/api-reference/reset-admin-password) – Change admin password (requires this JWT) # Create API Token for Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-api-token POST https://api.usedatabrain.com/api/v2/data-app/api-tokens Generate a new API token for a specific Data App to enable embed operations. Create a new API token for a Data App. API tokens are used to authenticate requests for embed operations such as creating embeds, generating guest tokens, and querying metrics. Each Data App can have multiple API tokens. This is useful for: * Separating tokens by environment (development, staging, production) * Rotating tokens without service interruption * Tracking API usage by token **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage API tokens across your organization. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app/api-tokens ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/api-tokens ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The name of the Data App to create the API token for. This must exactly match an existing Data App name. * Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to get all Data App names * Check your Databrain dashboard for Data App configurations * The name is case-sensitive A descriptive name/label for the API token. This helps identify the token's purpose. * Use descriptive names like "Production Token", "Development Token", "Partner API Key" * Include environment or purpose information * Keep names unique within each Data App for easy identification ## Response The newly generated API token (UUID format). Store this securely as it will be used for all embed operations. **Important:** The API key is only shown once. Store it securely immediately after creation. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/api-tokens \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{ "dataAppName": "Customer Portal Analytics", "name": "Production API Key" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/api-tokens', { method: 'POST', headers: { 'Authorization': 'Bearer service_token_xyz...', 'Content-Type': 'application/json' }, body: JSON.stringify({ dataAppName: 'Customer Portal Analytics', name: 'Production API Key' }) }); const data = await response.json(); console.log('New API Key:', data.key); // Store this key securely! ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/api-tokens" headers = { "Authorization": "Bearer service_token_xyz...", "Content-Type": "application/json" } payload = { "dataAppName": "Customer Portal Analytics", "name": "Production API Key" } response = requests.post(url, headers=headers, json=payload) data = response.json() print(f"New API Key: {data['key']}") # Store this key securely! ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class CreateApiToken { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "dataAppName": "Customer Portal Analytics", "name": "Production API Key" }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/api-tokens")) .header("Authorization", "Bearer service_token_xyz...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); // Store the key securely! } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type CreateApiTokenRequest struct { DataAppName string `json:"dataAppName"` Name string `json:"name"` } type CreateApiTokenResponse struct { Key string `json:"key"` Error interface{} `json:"error"` } func main() { requestBody := CreateApiTokenRequest{ DataAppName: "Customer Portal Analytics", Name: "Production API Key", } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/api-tokens", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer service_token_xyz...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result CreateApiTokenResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("New API Key: %s\n", result.Key) // Store this key securely! } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Customer Portal Analytics', 'name' => 'Production API Key' ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/data-app/api-tokens', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer service_token_xyz...', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); $result = json_decode($response, true); echo 'New API Key: ' . $result['key']; // Store this key securely! ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/api-tokens') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' request['Content-Type'] = 'application/json' request.body = { dataAppName: 'Customer Portal Analytics', name: 'Production API Key' }.to_json response = http.request(request) result = JSON.parse(response.body) puts "New API Key: #{result['key']}" # Store this key securely! ``` ```json 200 - Success theme={"dark"} { "key": "550e8400-e29b-41d4-a716-446655440000" } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"dataAppName\" is required" } } ``` ```json 400 - Data App Not Found theme={"dark"} { "error": { "code": "DATA_APP_NOT_FOUND", "message": "Data app not found" } } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - API token created successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | -------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid dataAppName or name | | `DATA_APP_NOT_FOUND` | 400 | Data App with given name not found | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## API Token Scope When an API token is created, it is automatically assigned the following scope: * **Access Metrics** - Query and retrieve metric data * **Access Dashboards** - Access and embed dashboards ## Quick Start Guide In **Settings** page, navigate to the **Service Tokens** section. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to confirm the Data App exists: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` Create a new API token for your Data App: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/api-tokens \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{"dataAppName": "My Data App", "name": "Production Token"}' ``` The response contains the API key. Store it securely as it won't be shown again: ```javascript theme={"dark"} // Store in environment variables process.env.DATABRAIN_API_KEY = response.key; // Or in a secrets manager await secretsManager.setSecret('databrain-api-key', response.key); ``` Use the new API key to create embeds and generate guest tokens: ```bash theme={"dark"} curl --request POST \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds' \ --header 'Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000' \ --header 'Content-Type: application/json' \ --data '{...}' ``` ## Best Practices Never commit API keys to version control. Use environment variables or secrets managers. Name tokens clearly (e.g., "Production API Key", "Dev Environment Token") Rotate API keys periodically for enhanced security using the [Rotate API Key](/developer-docs/helpers/api-reference/rotate-api-key) endpoint. Create separate tokens for development, staging, and production environments. ## Next Steps View all API tokens for a Data App Rotate API keys for enhanced security Use your API token to create embed configurations Generate guest tokens for your end users # Create an Empty Dashboard Embed Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-dashboard-embed POST https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds Create a new empty dashboard for multi-tenant scenarios where each client gets their own blank canvas. Create a **new empty dashboard** in your data app. This endpoint is designed for multi-tenant scenarios where each client needs their own dashboard instance to build upon. Use `templateDashboardId` to clone filters and settings from an existing dashboard. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/dashboard-embeds`. The old endpoint `/api/v2/dataApp/dashboard-embeds` will be deprecated soon. Please update your integrations to use the new endpoint format. This endpoint creates a **new empty dashboard**. To embed an **existing pre-built dashboard** from your workspace, use the [Embed a Pre-built Dashboard/Metric](/developer-docs/helpers/api-reference/create-embed) endpoint instead. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/dashboard-embeds ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Supported values: * `application/json` for pure JSON payloads * `multipart/form-data` when uploading a dashboard export JSON file via `importDashboardDataFile` ``` Content-Type: application/json ``` When using `multipart/form-data`, object/boolean/array fields (for example `accessSettings`, `metadata`, `importDashboardData`, `isImportMetrics`, `isRenameDashboard`, `schemaPairs`) can be sent as JSON strings. Databrain parses these before validation. `importDashboardDataFile` is a multipart file field (not a JSON body field). The uploaded file must be sent with MIME type `application/json` and contain a top-level `data` object. ## Request Body Unique identifier for the new dashboard. Must be unique within the data app. The name of the workspace where the dashboard will be created. Client ID for the dashboard owner. Used for multi-tenant isolation and row-level security. Dashboard ID to clone filters, grid margins, and layout settings from (optional). Custom metadata for the dashboard (optional). Allow users to create private metrics visible only to them (optional). Human-readable name for the embed configuration (optional). If not provided, the dashboard ID is used as the name. When `isRenameDashboard` is `true`, this value is also used as the underlying dashboard's display name. Description for the embed configuration (optional). When `true` and `templateDashboardId` is provided, metrics from the template dashboard are imported into the new dashboard (optional). Full dashboard configuration to import into the newly created client dashboard (optional). This should be the `data` object from a dashboard export payload (for example, from the [Export Dashboard](/developer-docs/helpers/api-reference/export-dashboard) API or the **Export Embed Dashboard** API). When `importDashboardData` is provided, Databrain skips `templateDashboardId`-based metric import and directly hydrates the new dashboard from this configuration. Optional JSON file upload alternative to `importDashboardData`. Upload a dashboard export JSON file (the payload that contains a top-level `data` object). When provided, Databrain reads `data` from the file and uses it as `importDashboardData`. If both `importDashboardData` and `importDashboardDataFile` are provided, `importDashboardDataFile` takes precedence. When `true` and `name` is provided, the created dashboard's display name is set to `name`. When `false` or omitted, the dashboard name is set to `{dashboardId}_{clientId}` (optional). Defaults to `false` if omitted. When `isImportMetrics` is `true` and `templateDashboardId` is provided, controls how metrics are imported: `GALLERY` or `METRIC` (optional). Optional. Same shape as **[Import Dashboard](/developer-docs/helpers/api-reference/import-dashboard)** **`schemaPairs`**: an array of objects; each object requires **`replaceSchema`** (string) and **`targetSchema`** (string). Use this when imported SQL references a schema name that should map to the target datamart schema. Typically used with **`importDashboardData`** or **`importDashboardDataFile`**. With **`multipart/form-data`**, send **`schemaPairs`** as a JSON-encoded string (see note above); the server parses it before Joi validation. Access control settings for the dashboard. The datamart name used in the embedded environment. Allow AI Pilot features (optional). Allow sending email reports. Allow managing metrics. Allow metric creation. Allow metric deletion. Allow layout changes to metrics. Allow updating metrics. Allow viewing of underlying data. Allow creating dashboard views. Optional. Enables end-user dashboard filter interactions in embedded mode. Optional allowlist for dashboard filterable columns. Each item must include `tableName` and `columns`. Fully qualified table name used in dashboard filters. Column names allowed for dashboard filter evaluation for the specified table. Optional. Enables end-user metric filter interactions in embedded mode. Optional allowlist for columns that end users can use in metric filters. Each item must include `tableName` and `columns`. Fully qualified table name used in metric filters. Column names allowed for metric filter evaluation for the specified table. Recommended join strategy for table relationships. * `single`: single worksheet mode (tables are pre-joined into one worksheet) * `multi`: multi-sheet mode (joins are resolved dynamically based on fields used in each chart) Legacy join strategy flag. Prefer using `accessSettings.joinModel` instead. Mode of metric creation (drag and drop or chat). List of allowed tables and client columns for table tenancy (optional). When provided, each item must include `name` and `clientColumn`. Table name. Required when the parent `tableTenancySettings` array is provided. Client-level column for table tenancy. Required when the parent `tableTenancySettings` array is provided. ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "dashboardId": "client-acme-dashboard", "workspaceName": "analytics-workspace", "clientId": "acme-corp-123", "templateDashboardId": "template-dashboard-001", "metadata": { "clientName": "Acme Corporation", "region": "North America" }, "isAllowPrivateMetricsByDefault": false, "name": "ACME Analytics Dashboard", "embedDescription": "Analytics dashboard for ACME Corp", "isImportMetrics": true, "isRenameDashboard": true, "metricImportMode": "GALLERY", "importDashboardData": { "...": "dashboard configuration exported from the Export Dashboard or Export Embed Dashboard API" }, "accessSettings": { "datamartName": "customer-analytics", "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowEndUserDashboardFilter": true, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "isAllowCreateDashboardView": true, "joinModel": "multi", "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "name": "sales_data", "clientColumn": "customer_id" } ] } }' ``` ```bash cURL (Multipart File Upload) theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --form 'dashboardId=client-acme-dashboard' \ --form 'workspaceName=analytics-workspace' \ --form 'clientId=acme-corp-123' \ --form 'name=ACME Analytics Dashboard' \ --form 'isRenameDashboard=true' \ --form 'accessSettings={"datamartName":"customer-analytics","isAllowEmailReports":false,"isAllowManageMetrics":true,"isAllowEndUserMetricFilter":true,"metricFilterColumns":[{"tableName":"public.sales_data","columns":["region","order_date"]}],"isAllowMetricCreation":true,"isAllowMetricDeletion":false,"isAllowMetricLayoutChange":true,"isAllowMetricUpdate":true,"isAllowUnderlyingData":false,"isAllowCreateDashboardView":true,"joinModel":"multi","metricCreationMode":"DRAG_DROP"}' \ --form 'importDashboardDataFile=@./dashboard-export.json;type=application/json' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ dashboardId: `client-${clientId}-dashboard`, workspaceName: 'analytics-workspace', clientId: clientId, templateDashboardId: 'template-dashboard-001', metadata: { clientName: 'Acme Corporation', createdAt: new Date().toISOString() }, isAllowPrivateMetricsByDefault: false, name: 'ACME Analytics Dashboard', embedDescription: 'Analytics dashboard for ACME Corp', isImportMetrics: true, isRenameDashboard: true, metricImportMode: 'GALLERY', importDashboardData: exportedDashboard.data, // from Export Dashboard or Export Embed Dashboard API accessSettings: { datamartName: 'customer-analytics', isAllowAiPilot: true, isAllowEmailReports: false, isAllowManageMetrics: true, isAllowEndUserDashboardFilter: true, dashboardFilterColumns: [ { tableName: 'public.sales_data', columns: ['customer_id', 'region', 'order_date'] } ], isAllowEndUserMetricFilter: true, metricFilterColumns: [ { tableName: 'public.sales_data', columns: ['region', 'order_date'] } ], isAllowMetricCreation: true, isAllowMetricDeletion: false, isAllowMetricLayoutChange: true, isAllowMetricUpdate: true, isAllowUnderlyingData: false, isAllowCreateDashboardView: true, joinModel: 'multi', metricCreationMode: 'DRAG_DROP', tableTenancySettings: [ { name: 'sales_data', clientColumn: 'customer_id' } ] } }) }); const data = await response.json(); console.log('New dashboard ID:', data.id, 'Name:', data.name); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests import json url = "https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } payload = { "dashboardId": f"client-{client_id}-dashboard", "workspaceName": "analytics-workspace", "clientId": client_id, "templateDashboardId": "template-dashboard-001", "metadata": { "clientName": "Acme Corporation", "region": "North America" }, "isAllowPrivateMetricsByDefault": False, "name": "ACME Analytics Dashboard", "embedDescription": "Analytics dashboard for ACME Corp", "isImportMetrics": True, "isRenameDashboard": True, "metricImportMode": "GALLERY", "importDashboardData": exported_dashboard["data"], # from Export Dashboard or Export Embed Dashboard API "accessSettings": { "datamartName": "customer-analytics", "isAllowEmailReports": False, "isAllowManageMetrics": True, "isAllowEndUserDashboardFilter": True, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": True, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "isAllowMetricCreation": True, "isAllowMetricDeletion": False, "isAllowMetricLayoutChange": True, "isAllowMetricUpdate": True, "isAllowUnderlyingData": False, "isAllowCreateDashboardView": True, "joinModel": "multi", "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "name": "sales_data", "clientColumn": "customer_id" } ] } } response = requests.post(url, headers=headers, data=json.dumps(payload)) data = response.json() print(f"New dashboard ID: {data['id']}, Name: {data.get('name')}") ``` ```json Success Response theme={"dark"} { "id": "client-acme-dashboard", "error": null, "name": "ACME Analytics Dashboard" } ``` ```json Error Response (400 - validation) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"accessSettings\" is required", "status": 400 } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DASHBOARD_ID", "message": "Dashboard already exists", "status": 400 } } ``` ```json Error Response (401) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Invalid Data App API key", "status": 401 } } ``` ## Response The ID of the created dashboard embed configuration. Error object if the request failed, otherwise `null`. The name of the embed configuration. Matches the request body `name` if provided, otherwise the `dashboardId`. Returned by the new endpoint (`/api/v2/data-app/dashboard-embeds`); the legacy endpoint returns only `id` and `error`. ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Dashboard created successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Code | Message | HTTP Status | | -------------------------- | --------------------------------- | ----------- | | `INVALID_REQUEST_BODY` | Request body validation failed | 400 | | `WORKSPACE_ID_ERROR` | Invalid workspace name | 400 | | `INVALID_DATA_APP_API_KEY` | Invalid Data App API key | 401 | | `CLIENT_ID_ERROR` | Invalid client id | 400 | | `INVALID_DASHBOARD_ID` | Dashboard already exists | 400 | | `TEMPLATE_DASHBOARD_ERROR` | Invalid template dashboard id | 400 | | `INVALID_DASHBOARD_DATA` | Uploaded JSON missing `data` | 400 | | `DASHBOARD_CREATE_ERROR` | Failed to create client dashboard | 400 or 500 | | `INTERNAL_SERVER_ERROR` | Internal server error | 500 | ## Quick Start Guide For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). Make a POST request with the required parameters: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/dashboard-embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "dashboardId": "client-acme-analytics", "clientId": "acme-corp-123", "workspaceName": "my-workspace", "accessSettings": { "datamartName": "my-datamart", "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowCreateDashboardView": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "joinModel": "multi", "metricCreationMode": "DRAG_DROP" } }' ``` To clone settings from an existing dashboard, add `templateDashboardId`. To also import metrics from the template, set `isImportMetrics: true` and optionally `metricImportMode` to `"GALLERY"` or `"METRIC"`. To use a custom display name for the dashboard (instead of `{dashboardId}_{clientId}`), set `name` and `isRenameDashboard: true`: ```json theme={"dark"} { "dashboardId": "client-acme-analytics", "clientId": "acme-corp-123", "templateDashboardId": "template-dashboard-001", "name": "ACME Analytics Dashboard", "isRenameDashboard": true, "isImportMetrics": true, "metricImportMode": "GALLERY", "accessSettings": { ... } } ``` Use the created dashboard ID to generate a guest token for your end users. See the [Guest Token API](/developer-docs/helpers/api-reference/token) for details. Use the dashboard ID and guest token in your web component: ```javascript theme={"dark"} ``` ## Use Cases Create isolated dashboards for each customer in your SaaS application. Use `templateDashboardId` to clone filters and settings from a master template. Set `isRenameDashboard: true` with `name` to give each client dashboard a human-readable display name instead of `{dashboardId}_{clientId}`. Automatically create dashboards during customer onboarding or upgrades. Ensure data isolation with `clientId` and row-level security settings. ## Next Steps Create secure tokens to access your new dashboard Embed existing dashboards that were built in the databrain platform Integrate dashboards into your application Set up row-level security for your dashboards # Create Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-data-app POST https://api.usedatabrain.com/api/v2/data-app Create a new Data App to organize and manage your embedded analytics. Create a new Data App in your organization. Data Apps serve as containers for organizing embed configurations, API tokens, and access controls for your embedded analytics. Data Apps are the top-level organizational unit for embedded analytics. Each Data App can contain multiple embed configurations and has its own set of API tokens for authentication. **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage Data Apps across your organization. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The unique name for the Data App. This name must be unique within your organization. * Names must be unique within your organization * Use descriptive names that indicate the purpose (e.g., "Customer Portal Analytics", "Partner Dashboard") * Avoid special characters that might cause URL encoding issues ## Response The name of the newly created Data App. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Customer Portal Analytics" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app', { method: 'POST', headers: { 'Authorization': 'Bearer service_token_xyz...', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Customer Portal Analytics' }) }); const data = await response.json(); console.log('Created Data App:', data.name); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app" headers = { "Authorization": "Bearer service_token_xyz...", "Content-Type": "application/json" } payload = { "name": "Customer Portal Analytics" } response = requests.post(url, headers=headers, json=payload) data = response.json() print(f"Created Data App: {data['name']}") ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class CreateDataApp { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "name": "Customer Portal Analytics" }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app")) .header("Authorization", "Bearer service_token_xyz...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type CreateDataAppRequest struct { Name string `json:"name"` } type CreateDataAppResponse struct { Name string `json:"name"` Error interface{} `json:"error"` } func main() { requestBody := CreateDataAppRequest{ Name: "Customer Portal Analytics", } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer service_token_xyz...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result CreateDataAppResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Created Data App: %s\n", result.Name) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Customer Portal Analytics' ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/data-app', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer service_token_xyz...', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); $result = json_decode($response, true); echo 'Created Data App: ' . $result['name']; ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' request['Content-Type'] = 'application/json' request.body = { name: 'Customer Portal Analytics' }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Created Data App: #{result['name']}" ``` ```json 200 - Success theme={"dark"} { "name": "Customer Portal Analytics" } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"name\" is required" } } ``` ```json 400 - Data App Already Exists theme={"dark"} { "error": { "code": "DATA_APP_ALREADY_EXISTS", "message": "Data app with the same name already exists" } } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Data App created successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ------------------------- | ----------- | -------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid name parameter | | `DATA_APP_ALREADY_EXISTS` | 400 | Data App with same name already exists | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide In **Settings** page, navigate to the **Service Tokens** section. Click the **"Generate Token"** button to create a new service token if you don't have one already. Make a POST request with a unique name for your Data App: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{"name": "My Analytics App"}' ``` After creating the Data App, create an API token to use for embed operations. See the [Create API Token](/developer-docs/helpers/api-reference/create-api-token) endpoint. Use the API token to create embed configurations for your dashboards and metrics. ## Next Steps View all Data Apps in your organization Generate API tokens for your Data App Create embed configurations for dashboards Remove Data Apps you no longer need # Create Datamart Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datamart POST https://api.usedatabrain.com/api/v2/data-app/datamarts Create a new datamart to organize and manage your data sources with custom table and column configurations. Create datamarts to organize your data sources into logical business units. Datamarts provide structured access to your datasource tables and columns with optional schema support. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/datamarts`. The old endpoint `/api/v2/dataApp/datamarts` will be deprecated soon. Please update your integrations to use the new endpoint format. Datamarts help organize data sources by defining which tables and columns are accessible. Tenancy settings are optional and can be omitted if multi-tenant data isolation is handled at the application level. Ensure your datasource exists before creating a datamart. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app/datamarts ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/data-app/datamarts ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ```bash Authentication theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' \ --data '{ "name": "demo-sales-default-1", "datasourceName": "Bigquery", "tableList": [ { "schemaName": "databrain_dev2", "name": "demo_sales", "label": "Demo Sales", "clientColumn": "client id", "isHide": false, "columns": [ { "name": "client id", "alias": "client_id", "label": "Client ID", "isHide": false, "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT", "defaultSort": "ASC" }, { "name": "store id", "alias": "store_id", "label": "Store ID", "isHide": false, "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT", "defaultSort": "ASC" }, { "name": "quantity sold", "alias": "quantity_sold", "label": "Quantity Sold", "isHide": false, "allowAggregate": true, "defaultAggregation": "SUM", "defaultSort": "DESC" } ] } ] }' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the datamart to create. Must be unique within your organization — the API will reject the request with an error if a datamart with the same name already exists. * Use descriptive names (e.g., "sales-analytics", "customer-data") * Alphanumeric characters and hyphens recommended * Must be unique within your organization (enforced server-side) * Cannot be changed after creation The datasource to which this datamart belongs. Must match an existing datasource in your organization. * Check your datasources list in the DataBrain dashboard * Use the exact name as it appears in your datasource configuration * Names are case-sensitive Array of tables with columns to include in the datamart. Must be non-empty. Table name from your datasource. Optional schema name (required only for schema-based datasources like PostgreSQL, SQL Server). Optional column name in this table that identifies the client/tenant. This column is used for multi-tenant data isolation at the table level. Must exist in the table schema. * Used for table-level tenancy when `tenancyLevel` is `TABLE` * The column should contain client/tenant identifiers Optional flag to hide the table from the datamart interface. Optional label for the table to provide a human-readable display name. When provided, this label can be used in the UI instead of the technical table name for better readability. * Provides a user-friendly display name for the table * Useful when table names are cryptic or technical * Does not affect the actual table reference in queries Optional wildcard index pattern for OpenSearch tables. When set, this value is used as the table name in queries, enabling you to query multiple OpenSearch indices that match a pattern. * Only applicable to **OpenSearch** datasources * Accepts a valid OpenSearch index wildcard pattern (e.g., `logs-*`, `events-2024-*`) * When set, the wildcard value is used instead of the exact `name` when constructing the FROM clause * Allows a single datamart table to cover multiple time-partitioned or sharded OpenSearch indices List of column objects for this table. Must be non-empty. Column name from the table. Optional alias for the column to display a different name. Optional label for the column for better readability. Optional flag to hide the column from the datamart interface. Optional flag to mark this as a custom/calculated column. When `true`, the `sql` field is required to define the column's SQL expression. * Custom columns allow you to define calculated fields using SQL expressions * The `name` field should reference an existing column from the datasource schema * Use the `alias` field to give the calculated column a custom display name * The SQL expression can reference other columns from the same table * Useful for derived metrics, concatenations, or transformations SQL expression that defines the calculated value for a custom column. **Required when** `isCustomColumn` is `true`. The expression can reference other columns from the same table. * Simple calculation: `quantity * unit_price` * Date extraction: `EXTRACT(YEAR FROM order_date)` * String concatenation: `CONCAT(first_name, ' ', last_name)` * Case statement: `CASE WHEN status = 'active' THEN 1 ELSE 0 END` Optional flag to indicate if this column should be treated as an aggregate column. When `true`, the column is marked as `AGGREGATE` drop type for metric calculations. * Aggregate columns are used for pre-aggregated metrics * Affects how the column behaves in metric calculations and drag-drop operations * Common for SUM, COUNT, AVG type pre-calculated values Optional flag to enable default aggregation for the column. When `true`, Databrain uses the value set in `defaultAggregation` when the column is added as a measure. Optional field to define the default aggregation applied to the column when used as a measure. ```json theme={"dark"} { "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT" } ``` Optional flag to enable timezone conversion for this column. When `true`, the column's datetime values are converted using the timezone passed as `params.timezone` in the guest token at query execution time. This field has no effect unless `params.timezone` is set in the guest token. See [Timezone Handling in Guest Token](/developer-docs/solutions-alchemy/guest-token-timezone) for the full setup guide. * Apply to datetime or timestamp columns that store values in UTC or a fixed timezone * The timezone is sourced from `params.timezone` in the guest token — not a user or workspace setting * Supported datasources: Postgres, CockroachDB, Trino, Athena, BigQuery, MSSQL, OpenSearch, Databricks, Clickhouse, Redshift, Snowflake * Has no effect on non-datetime column types Optional default sort direction for the column. Supported values are `ASC` and `DESC`. The value is propagated to data-app embed access settings and used as the initial sort direction when this column is selected during metric creation. Pass an empty string (`""`) or `null`, or omit this field, to leave the column without a default sort. Values are case-sensitive; lowercase values such as `"asc"` fail validation. Multi-tenant configuration for the datamart. Defines how data is isolated between different tenants/clients. Optional - if not provided, the datamart will be created without explicit tenancy settings. * **TABLE level**: Uses a dedicated table to map client identifiers * **DATABASE level**: Each client has a separate database * **MULTI\_DATABASE level**: Supports multi-database tenancy with an optional primary database * Optional - can be omitted if tenancy is handled at the application level The level at which tenant isolation occurs. Must be one of: `TABLE`, `DATABASE`, or `MULTI_DATABASE`. * `TABLE`: Client mapping is stored in a specific table (most common) * `DATABASE`: Each client has a separate database instance * `MULTI_DATABASE`: Tenancy spans multiple databases with optional default routing via `primaryDatabase` **Required when** `tenancySettings` is provided. If `tenancySettings` is omitted, this field is not needed. Data type of the client identifier column. Must be either `NUMBER` or `STRING`. **Required when** `tenancyLevel` is `TABLE`. Optional primary database name used for `DATABASE` and `MULTI_DATABASE` tenancy levels. Set to `null` when you do not want a default database. **Note:** The API accepts this field for all tenancy levels. It is primarily used by `DATABASE` and `MULTI_DATABASE`. Schema name where the client mapping table is located. **Required when** `tenancyLevel` is `TABLE`. Name of the table that contains client mapping information. **Required when** `tenancyLevel` is `TABLE`. Column name in the mapping table that stores the client identifier. **Required when** `tenancyLevel` is `TABLE`. Primary key column of the client mapping table. **Required when** `tenancyLevel` is `TABLE`. Optional array of table relationships to define how tables in the datamart are connected. Relationships enable joins between tables for more complex queries. * Define how tables relate to each other (e.g., orders.customer\_id → customers.id) * Supports different join types and cardinalities * Useful for creating metrics that span multiple tables * Optional - datamarts can work without relationships for single-table queries Name of the parent table in the relationship. Column name in the parent table that participates in the relationship. Name of the child table in the relationship. Column name in the child table that participates in the relationship. A descriptive name for the relationship (e.g., "orders\_to\_customers"). The cardinality of the relationship. Must be one of: `ManyToMany`, `ManyToOne`, `OneToMany`, `OneToOne`. **Optional:** Can be omitted or set to `null` if not specified. The type of SQL join to use. Must be one of: `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL JOIN`. **Optional:** Can be omitted or set to `null` if not specified. ## Response The name of the created datamart (same as the input name). Error object if the request failed, otherwise `null` for successful requests. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "demo-sales-default-1", "datasourceName": "Bigquery", "tableList": [ { "schemaName": "databrain_dev2", "name": "demo_sales", "label": "Demo Sales", "clientColumn": "client id", "isHide": false, "columns": [ { "name": "client id", "alias": "client_id", "label": "Client ID", "isHide": false, "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT", "defaultSort": "ASC" }, { "name": "store id", "alias": "store_id", "label": "Store ID", "isHide": false, "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT", "defaultSort": "ASC" }, { "name": "quantity sold", "alias": "quantity_sold", "label": "Quantity Sold", "isHide": false, "allowAggregate": true, "defaultAggregation": "SUM", "defaultSort": "DESC" } ] } ] }' ``` ```bash cURL - Without Tenancy Settings theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "analytics-datamart", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Sales Orders", "clientColumn": "tenant_id", "columns": [ { "name": "order_id", "alias": "id", "label": "Order ID" }, { "name": "order_date", "alias": "date", "label": "Order Date" } ] } ] }' ``` ```bash cURL - Multi-Database Tenancy theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "regional-sales-multi-db", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "columns": [ { "name": "order_id" }, { "name": "region" } ] } ], "tenancySettings": { "tenancyLevel": "MULTI_DATABASE", "primaryDatabase": "core_analytics" } }' ``` ```bash cURL - With Custom Columns theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "sales-with-calculations", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Customer Orders", "columns": [ { "name": "order_id", "alias": "id", "label": "Order ID" }, { "name": "quantity", "label": "Quantity" }, { "name": "unit_price", "alias": "total_revenue", "label": "Total Revenue", "isCustomColumn": true, "sql": "quantity * unit_price" }, { "name": "order_date", "alias": "order_year", "label": "Order Year", "isCustomColumn": true, "sql": "EXTRACT(YEAR FROM order_date)" }, { "name": "created_at", "label": "Created At", "isApplyTimezone": true } ] } ] }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'sales-analytics', datasourceName: 'postgres-main', tableList: [ { schemaName: 'public', name: 'orders', label: 'Customer Orders', clientColumn: 'tenant_id', isHide: false, columns: [ { name: 'order_id', alias: 'id', label: 'Order ID', isHide: false }, { name: 'customer_id', label: 'Customer', isHide: false }, { name: 'order_date', alias: 'date', label: 'Order Date', isHide: false } ] } ], tenancySettings: { tenancyLevel: 'TABLE', clientColumnType: 'STRING', schemaName: 'public', tableName: 'client_mapping', tableClientNameColumn: 'client_id', tablePrimaryKeyColumn: 'id' }, relationships: [ { parentTableName: 'orders', parentColumnName: 'customer_id', childTableName: 'customers', childColumnName: 'id', relationshipName: 'orders_to_customers', cardinality: 'ManyToOne', join: 'LEFT JOIN' } ] }) }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/data-app/datamarts', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'name': 'sales-analytics', 'datasourceName': 'postgres-main', 'tableList': [ { 'schemaName': 'public', 'name': 'orders', 'columns': [ { 'name': 'order_id', 'alias': 'id', 'label': 'Order ID' }, { 'name': 'customer_id', 'label': 'Customer' }, { 'name': 'order_date', 'alias': 'date', 'label': 'Order Date' } ] } ], 'tenancySettings': { 'tenancyLevel': 'TABLE', 'clientColumnType': 'STRING', 'schemaName': 'public', 'tableName': 'client_mapping', 'tableClientNameColumn': 'client_id', 'tablePrimaryKeyColumn': 'id' }, 'relationships': [ { 'parentTableName': 'orders', 'parentColumnName': 'customer_id', 'childTableName': 'customers', 'childColumnName': 'id', 'relationshipName': 'orders_to_customers', 'cardinality': 'ManyToOne', 'join': 'LEFT JOIN' } ] } ) ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { name: 'sales-analytics', datasourceName: 'postgres-main', tableList: [ { schemaName: 'public', name: 'orders', label: 'Customer Orders', columns: [ { name: 'order_id', alias: 'id', label: 'Order ID' }, { name: 'customer_id', label: 'Customer' }, { name: 'order_date', alias: 'date', label: 'Order Date' } ] } ], tenancySettings: { tenancyLevel: 'TABLE', clientColumnType: 'STRING', schemaName: 'public', tableName: 'client_mapping', tableClientNameColumn: 'client_id', tablePrimaryKeyColumn: 'id' }, relationships: [ { parentTableName: 'orders', parentColumnName: 'customer_id', childTableName: 'customers', childColumnName: 'id', relationshipName: 'orders_to_customers', cardinality: 'ManyToOne', join: 'LEFT JOIN' } ] }.to_json response = http.request(request) ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainDatamartAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """{ "name": "sales-analytics", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Customer Orders", "columns": [ { "name": "order_id", "alias": "id", "label": "Order ID" }, { "name": "customer_id", "label": "Customer" }, { "name": "order_date", "alias": "date", "label": "Order Date" } ] } ], "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "client_mapping", "tableClientNameColumn": "client_id", "tablePrimaryKeyColumn": "id" }, "relationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/datamarts")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type DatamartRequest struct { Name string `json:"name"` DatasourceName string `json:"datasourceName"` TableList []TableInfo `json:"tableList"` TenancySettings TenancySettings `json:"tenancySettings"` } type TableInfo struct { SchemaName string `json:"schemaName"` Name string `json:"name"` Label string `json:"label,omitempty"` Columns []ColumnInfo `json:"columns"` } type ColumnInfo struct { Name string `json:"name"` Alias string `json:"alias,omitempty"` Label string `json:"label,omitempty"` } type TenancySettings struct { TenancyLevel string `json:"tenancyLevel"` ClientColumnType string `json:"clientColumnType"` SchemaName string `json:"schemaName"` TableName string `json:"tableName"` TableClientNameColumn string `json:"tableClientNameColumn"` TablePrimaryKeyColumn string `json:"tablePrimaryKeyColumn"` } func main() { reqData := DatamartRequest{ Name: "sales-analytics", DatasourceName: "postgres-main", TableList: []TableInfo{ { SchemaName: "public", Name: "orders", Columns: []ColumnInfo{ {Name: "order_id", Alias: "id", Label: "Order ID"}, {Name: "customer_id", Label: "Customer"}, {Name: "order_date", Alias: "date", Label: "Order Date"}, }, }, }, TenancySettings: TenancySettings{ TenancyLevel: "TABLE", ClientColumnType: "STRING", SchemaName: "public", TableName: "client_mapping", TableClientNameColumn: "client_id", TablePrimaryKeyColumn: "id", }, } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/datamarts", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Datamart created successfully") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics', 'datasourceName' => 'postgres-main', 'tableList' => [ [ 'schemaName' => 'public', 'name' => 'orders', 'label' => 'Customer Orders', 'columns' => [ [ 'name' => 'order_id', 'alias' => 'id', 'label' => 'Order ID' ], [ 'name' => 'customer_id', 'label' => 'Customer' ], [ 'name' => 'order_date', 'alias' => 'date', 'label' => 'Order Date' ] ] ] ], 'tenancySettings' => [ 'tenancyLevel' => 'TABLE', 'clientColumnType' => 'STRING', 'schemaName' => 'public', 'tableName' => 'client_mapping', 'tableClientNameColumn' => 'client_id', 'tablePrimaryKeyColumn' => 'id' ], 'relationships' => [ [ 'parentTableName' => 'orders', 'parentColumnName' => 'customer_id', 'childTableName' => 'customers', 'childColumnName' => 'id', 'relationshipName' => 'orders_to_customers', 'cardinality' => 'ManyToOne', 'join' => 'LEFT JOIN' ] ] ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); echo "Datamart ID: " . $result['id']; ?> ``` ```json 200 - Success theme={"dark"} { "id": "sales-analytics", "error": null } ``` ```json 400 - Bad Request theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Table list cannot be empty" } } ``` ```json 400 - Duplicate Datamart Name theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Datamart name already exists" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid or missing API key" } } ``` ## Errors | HTTP Status | Error Code | Description | | ----------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `200` | - | **Success** - Datamart created successfully | | `200` | - | **Success** - Datamart created successfully | | `400` | `INVALID_REQUEST_BODY` | Invalid request parameters. Common causes: missing required fields, empty table list, invalid table/column structure, invalid schema/table names, invalid column names, validation errors from Joi schema, or **duplicate datamart name** (`"Datamart name already exists"`). | | `400` | `AUTH_ERROR` | Invalid or expired service token | | `400` | `DATASOURCE_NAME_ERROR` | The specified datasource doesn't exist or you don't have access to it | | `500` | `INTERNAL_SERVER_ERROR` | Server error occurred. Contact support if error persists | ## Quick Start Guide Ensure your datasource exists and is properly configured. You'll need the exact datasource name as it appears in your DataBrain workspace. Identify the tables and columns you want to include in your datamart: ```json theme={"dark"} { "name": "sales-analytics", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Customer Orders", "clientColumn": "tenant_id", "isHide": false, "columns": [ {"name": "order_id", "alias": "id", "label": "Order ID", "isHide": false}, {"name": "customer_id", "label": "Customer", "isHide": false}, {"name": "order_date", "alias": "date", "label": "Order Date", "isHide": false} ] } ], "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "client_mapping", "tableClientNameColumn": "client_id", "tablePrimaryKeyColumn": "id" }, "relationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] } ``` Make the API call to create your datamart: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "sales-analytics", "datasourceName": "postgres-main", "tableList": [ { "schemaName": "public", "name": "orders", "clientColumn": "tenant_id", "isHide": false, "columns": [ {"name": "order_id", "alias": "id", "label": "Order ID", "isHide": false}, {"name": "customer_id", "label": "Customer", "isHide": false} ] } ], "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "client_mapping", "tableClientNameColumn": "client_id", "tablePrimaryKeyColumn": "id" }, "relationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] }' ``` Reference your new datamart in embed configurations: ```javascript theme={"dark"} const embedConfig = await createEmbedConfiguration({ dashboardId: 'your-dashboard-id', embedType: 'dashboard', workspaceName: 'your-workspace', accessSettings: { datamartName: 'sales-analytics', // Your new datamart // ... other settings } }); ``` ## Next Steps View all datamarts in your organization Remove datamarts you no longer need Use your datamart in embed configurations Learn how to get started with DataBrain embedding # Create Datasource Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-datasource POST https://api.usedatabrain.com/api/v2/datasource Create a new datasource connection to your data infrastructure. Supports multiple database types and cloud services. Create a new datasource connection to integrate your database or data warehouse with DataBrain. The API validates credentials, tests the connection, and automatically caches the schema for immediate use. Before creating a datasource, ensure you have valid credentials for your database or data warehouse. The API will test the connection before creating the datasource. Supported datasource types include Snowflake, PostgreSQL, MySQL, BigQuery, Databricks, and many more. ## Endpoint ``` POST https://api.usedatabrain.com/api/v2/datasource ``` ## Self-hosted Databrain Endpoint ``` POST /api/v2/datasource ``` ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. ```bash Authentication theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The type of datasource to create. Must be one of the supported datasource types. **Supported types:** * `snowflake` - Snowflake data warehouse * `postgres` - PostgreSQL database * `redshift` - Amazon Redshift * `cockroachdb` - CockroachDB * `mysql` - MySQL database * `mongodb` - MongoDB database * `clickhouse` - ClickHouse database * `singlestore` - SingleStore database * `bigquery` - Google BigQuery * `databricks` - Databricks * `elasticsearch` - Elasticsearch * `opensearch` - OpenSearch * `mssql` - Microsoft SQL Server * `awss3` - Amazon S3 * `csv` - CSV files * `firebolt` - Firebolt * `athena` - Amazon Athena * `trino` - Trino The datasource type determines which credential fields are required. Each datasource type has specific connection requirements documented in the credentials section. Connection credentials for the datasource. The structure varies by datasource type, but all types require a `name` field. All datasource types require: * `name` (string, required) - Unique name for the datasource within your organization Unique name for the datasource. This name will be used to reference the datasource in other APIs and configurations. * Use descriptive names (e.g., "production-postgres", "analytics-snowflake") * Must be unique within your organization * Alphanumeric characters, hyphens, and underscores recommended * Case-sensitive Multi-tenant configuration for the datasource. Defines how data is isolated between different tenants/clients. Optional - if not provided, the datasource will be created without explicit tenancy settings. * **TABLE level**: Uses a dedicated table to map client identifiers * **DATABASE level**: Each client has a separate database * Optional - can be omitted if tenancy is handled at the application level The level at which tenant isolation occurs. Must be one of: `TABLE` or `DATABASE`. * `TABLE`: Client mapping is stored in a specific table (most common) * `DATABASE`: Each client has a separate database instance **Required when** `tenancySettings` is provided. If `tenancySettings` is omitted, this field is not needed. Data type of the client identifier column. Must be either `NUMBER` or `STRING`. **Required when** `tenancyLevel` is `TABLE`. Schema name where the client mapping table is located. **Required when** `tenancyLevel` is `TABLE`. Name of the table that contains client mapping information. **Required when** `tenancyLevel` is `TABLE`. Column name in the mapping table that stores the client identifier. **Required when** `tenancyLevel` is `TABLE`. Primary key column of the client mapping table. **Required when** `tenancyLevel` is `TABLE`. ### Datasource-Specific Credentials The credentials object structure depends on the `datasourceType`. Below are examples for common datasource types: Datasource-specific credential fields. The required fields depend on the `datasourceType`. Snowflake account hostname (e.g., `your-account.snowflakecomputing.com`) Snowflake username Snowflake role to use Snowflake warehouse name Snowflake database name Snowflake schema name Authentication method: `"username/password"` or `"Key-pair authentication"` Password (required if credentials is `"username/password"`) Private key (required if credentials is `"Key-pair authentication"`) Passphrase for the private key (optional) Database hostname or IP address Database port number (1-65535) Database username Database password Database name Schema name Enable SSL mode (optional) SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH server hostname (required if sshTunnel is `"enable"`) SSH server port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) CockroachDB hostname or IP address Database port number (1-65535) Database username Database password Database name Schema name Enable SSL mode (optional) SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH server hostname (required if sshTunnel is `"enable"`) SSH server port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) JSON string containing Google Cloud service account credentials Google Cloud project ID BigQuery dataset location (e.g., `"US"`, `"EU"`) BigQuery dataset ID (optional) Database hostname or IP address Database port number (1-65535) Database username. Note: Uses `user` not `username` for these datasource types. Database password SQL Server hostname or IP address. Note: Uses `server` not `host` for MSSQL. Database port number (1-65535) Database username. Note: Uses `user` not `username` for MSSQL. Database password Database name (optional) Disable database selection (optional) Optional MSSQL read-only routing hint. When `true`, Databrain connects with read-only intent for MSSQL workloads. Database hostname or IP address Database port number (1-65535) Database username Database password Database name Databricks server hostname Databricks HTTP path Databricks access token Server type: `"elastic-cloud"`, `"open-cloud"`, or `"self-managed"` Cloud ID (required if server\_type is `"elastic-cloud"` or `"open-cloud"`) Server URL (required if server\_type is `"self-managed"`) Username (required unless `disableAuth` is `true`) Password (required unless `disableAuth` is `true`) Disable authentication (optional, default `false`). Only valid when server\_type is `"self-managed"`. Ignore certificate verification (optional) Ignore SSL (optional) Server type: `"elastic-cloud"`, `"open-cloud"`, or `"self-managed"` Cloud ID (required if server\_type is `"elastic-cloud"` or `"open-cloud"`) Server URL (required if server\_type is `"self-managed"`) Username (required unless `disableAuth` is `true`) Password (required unless `disableAuth` is `true`) Disable authentication (optional, default `false`). Only valid when server\_type is `"self-managed"`. Ignore certificate verification (optional) Ignore SSL (optional) Firebolt client ID Firebolt client secret Firebolt account name Database name Engine name Schema name (optional) Athena database name S3 output bucket for query results AWS access key ID AWS region AWS secret access key Datasource ID (optional) Trino hostname or IP address Database port number (1-65535) Trino catalog name Schema name Username Password SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH host (required if sshTunnel is `"enable"`) SSH port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) Name for the CSV datasource S3 bucket name Path within the bucket (optional, can be empty string) AWS region (e.g., `"us-east-1"`) Table level: `"File"` or `"Folder"` (optional) AWS access key ID AWS secret access key ## Response The name of the created datasource (same as credentials.name). Error field, null when successful. Not included in successful responses. ## Examples ```bash cURL - PostgreSQL Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "postgres", "credentials": { "name": "production-postgres", "host": "db.example.com", "port": 5432, "username": "dbuser", "password": "securepassword", "database": "analytics", "schema": "public" } }' ``` ```bash cURL - Snowflake Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "snowflake", "credentials": { "name": "analytics-snowflake", "host": "account.snowflakecomputing.com", "username": "user@example.com", "role": "ANALYST", "warehouse": "COMPUTE_WH", "database": "ANALYTICS", "schema": "PUBLIC", "credentials": "username/password", "password": "securepassword" } }' ``` ```bash cURL - MSSQL Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "mssql", "credentials": { "name": "production-mssql", "server": "sqlserver.example.com", "port": 1433, "user": "sqluser", "password": "securepassword", "database": "analytics", "readOnlyIntent": true } }' ``` ```bash cURL - CockroachDB Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "cockroachdb", "credentials": { "name": "production-cockroachdb", "host": "cockroach.example.com", "port": 26257, "username": "dbuser", "password": "securepassword", "database": "analytics", "schema": "public" } }' ``` ```bash cURL - OpenSearch Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "opensearch", "credentials": { "name": "production-opensearch", "server_type": "self-managed", "server_url": "https://opensearch.example.com:9200", "username": "admin", "password": "securepassword" } }' ``` ```bash cURL - Elasticsearch Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "elasticsearch", "credentials": { "name": "production-elasticsearch", "server_type": "elastic-cloud", "cloud_id": "my-deployment:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyQ...", "username": "elastic", "password": "securepassword" } }' ``` ```bash cURL - Trino Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "trino", "credentials": { "name": "production-trino", "host": "trino.example.com", "port": 8080, "catalog": "hive", "schema": "analytics", "username": "trinouser", "password": "securepassword" } }' ``` ```bash cURL - With Tenancy Settings theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "postgres", "credentials": { "name": "multi-tenant-postgres", "host": "db.example.com", "port": 5432, "username": "dbuser", "password": "securepassword", "database": "analytics", "schema": "public" }, "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "clients", "tableClientNameColumn": "client_name", "tablePrimaryKeyColumn": "client_id" } }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/datasource', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datasourceType: 'postgres', credentials: { name: 'production-postgres', host: 'db.example.com', port: 5432, username: 'dbuser', password: 'securepassword', database: 'analytics', schema: 'public' } }) }); const data = await response.json(); if (data.error) { console.error('Error:', data.error); } else { console.log('Datasource created:', data.name); } ``` ```python Python theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/datasource', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'datasourceType': 'postgres', 'credentials': { 'name': 'production-postgres', 'host': 'db.example.com', 'port': 5432, 'username': 'dbuser', 'password': 'securepassword', 'database': 'analytics', 'schema': 'public' } } ) data = response.json() if data.get('error'): print('Error:', data['error']) else: print('Datasource created:', data['name']) ``` ```json 200 - Success theme={"dark"} { "name": "production-postgres" } ``` ```json 400 - Bad Request theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid credentials for postgres: \"host\" is required", "status": 400 } } ``` ```json 400 - Duplicate Name theme={"dark"} { "error": { "code": "DATASOURCE_NAME_ERROR", "message": "Datasource name already exists, please use unique name", "status": 400 } } ``` ```json 400 - Connection Test Failed theme={"dark"} { "error": { "code": "CREDENTIAL_TEST_FAILED", "message": "Failed to connect to datasource", "status": 400 } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "AUTHENTICATION_ERROR", "status": 401 } } ``` ## Error Codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing required fields or invalid credential structure | | `DATASOURCE_NAME_ERROR` | 400 | Datasource name already exists | | `CREDENTIAL_TEST_FAILED` | 400 | Connection test failed | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing service token | | `SCHEMA_CACHE_FAILED` | 500 | Schema caching failed | | `CREATE_DATASOURCE_FAILED` | 500 | Internal error during datasource creation | | `INTERNAL_SERVER_ERROR` | 500 | Server error occurred | ## Next Steps View all datasources in your organization Update datasource credentials or configuration Sync datasource schema after creation Create a datamart using your new datasource # Embed a Pre-built Dashboard/Metric Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-embed POST https://api.usedatabrain.com/api/v2/data-app/embeds Create an embed for an existing dashboard or metric that was built by your data analyst. Embed **existing dashboards or metrics** from your workspace. Use this endpoint when a dashboard has already been created in the DataBrain platform and you want to make it available for embedding in your application. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/embeds`. The old endpoint `/api/v2/dataApp/embeds` will be deprecated soon. Please update your integrations to use the new endpoint format. This endpoint embeds **existing dashboards/metrics** from your workspace. To create a **new empty dashboard** for multi-tenant scenarios, use the [Create an Empty Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed) endpoint instead. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app/embeds ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/embeds ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Existing dashboard ID to embed. This dashboard must already exist in your workspace. Type of embed configuration: `dashboard` or `metric`. Metric ID to embed. Required if embedType is `metric`. The name of the workspace where the embed configuration will be created. Optional human-readable name for the embed configuration. If not provided, the embed ID will be used as the name. Access control settings for the embedded view. Required when `embedType` is `dashboard`. Optional when `embedType` is `metric`. The datamart name used in the embedded environment. Required when `embedType` is `dashboard`. Allow AI Pilot features (optional). Allow sending email reports. Allow managing metrics. Allow creating dashboard views. Optional. Enables end-user dashboard filter interactions in embedded mode. Optional allowlist for dashboard filterable columns. Each item must include `tableName` and `columns`. Fully qualified table name used in dashboard filters. Column names allowed for dashboard filter evaluation for the specified table. Optional. Enables end-user metric filter interactions in embedded mode. Optional allowlist for columns that end users can use in metric filters. Each item must include `tableName` and `columns`. Fully qualified table name used in metric filters. Column names allowed for metric filter evaluation for the specified table. Allow metric creation. Allow metric deletion. Allow metric layout changes. Allow updating metrics. Allow viewing underlying data. Recommended join strategy for table relationships. * `single`: single worksheet mode (tables are pre-joined into one worksheet) * `multi`: multi-sheet mode (joins are resolved dynamically based on fields used in each chart) Legacy join strategy flag. Prefer using `accessSettings.joinModel` instead. Mode of metric creation (drag and drop or chat). Multi-tenant table access configuration (optional). Table name for tenancy configuration. Required when `tableTenancySettings` is provided. Column name for client-level filtering. Required when `tableTenancySettings` is provided. ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "dashboardId": "dash_12345", "embedType": "dashboard", "workspaceName": "analytics-workspace", "name": "Sales Dashboard Embed", "accessSettings": { "datamartName": "sales-data", "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowCreateDashboardView": true, "isAllowEndUserDashboardFilter": true, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "joinModel": "multi", "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "name": "sales_data", "clientColumn": "customer_id" } ] } }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ dashboardId: 'dash_12345', embedType: 'dashboard', workspaceName: 'analytics-workspace', name: 'Sales Dashboard Embed', accessSettings: { datamartName: 'sales-data', isAllowEmailReports: false, isAllowManageMetrics: true, isAllowCreateDashboardView: true, isAllowEndUserDashboardFilter: true, dashboardFilterColumns: [ { tableName: 'public.sales_data', columns: ['customer_id', 'region', 'order_date'] } ], isAllowEndUserMetricFilter: true, metricFilterColumns: [ { tableName: 'public.sales_data', columns: ['region', 'order_date'] } ], isAllowMetricCreation: true, isAllowMetricDeletion: false, isAllowMetricLayoutChange: true, isAllowMetricUpdate: true, isAllowUnderlyingData: false, joinModel: 'multi', metricCreationMode: 'DRAG_DROP', tableTenancySettings: [ { name: 'sales_data', clientColumn: 'customer_id' } ] } }) }); const data = await response.json(); console.log('Embed configuration ID:', data.id); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests import json url = "https://api.usedatabrain.com/api/v2/data-app/embeds" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } payload = { "dashboardId": "dash_12345", "embedType": "dashboard", "workspaceName": "analytics-workspace", "name": "Sales Dashboard Embed", "accessSettings": { "datamartName": "sales-data", "isAllowEmailReports": False, "isAllowManageMetrics": True, "isAllowCreateDashboardView": True, "isAllowEndUserDashboardFilter": True, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": True, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "isAllowMetricCreation": True, "isAllowMetricDeletion": False, "isAllowMetricLayoutChange": True, "isAllowMetricUpdate": True, "isAllowUnderlyingData": False, "joinModel": "multi", "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "name": "sales_data", "clientColumn": "customer_id" } ] } } response = requests.post(url, headers=headers, data=json.dumps(payload)) data = response.json() print(f"Embed configuration ID: {data['id']}") ``` ```json Success Response theme={"dark"} { "id": "embed_abc123def456", "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_WORKSPACE_NAME", "message": "Invalid workspace name", "status": 400 } } ``` ```json Error Response (404) theme={"dark"} { "error": { "code": "INVALID_DASHBOARD_ID", "message": "Dashboard not found", "status": 404 } } ``` ## Response Unique identifier for the created embed configuration. Error object if the request failed, otherwise `null`. ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Embed configuration created successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `404` | **Not Found** - Dashboard or metric not found | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------- | | `INVALID_WORKSPACE_NAME` | 404 | Workspace not found | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INVALID_DASHBOARD_ID` | 404 | Dashboard not found | | `INVALID_METRIC_ID` | 404 | Metric not found | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). First, create and configure your dashboard in the DataBrain workspace with all the metrics and visualizations you want to embed. Make a POST request to embed your existing dashboard: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "dashboardId": "existing-dashboard-id", "embedType": "dashboard", "workspaceName": "my-workspace", "accessSettings": { "datamartName": "my-datamart", "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowCreateDashboardView": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "joinModel": "multi", "metricCreationMode": "DRAG_DROP" } }' ``` To embed just one metric instead of the entire dashboard, use `embedType: "metric"`: ```json theme={"dark"} { "dashboardId": "existing-dashboard-id", "embedType": "metric", "metricId": "metric-123", "workspaceName": "my-workspace", // ... accessSettings } ``` Use the embed ID to generate a guest token for your end users. See the [Guest Token API](/developer-docs/helpers/api-reference/token) for details. Use the embed ID and guest token in your web component: ```javascript theme={"dark"} ``` ## Next Steps Create secure tokens for your embed configurations Create new empty dashboards for multi-tenant scenarios Modify existing embed configurations Learn how to integrate embeds in your application # Create Semantic Layer Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-semantic-layer POST https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer Create a semantic layer for a datamart by adding table descriptions, column metadata, and feedback. Add semantic metadata to a datamart that doesn't have a semantic layer yet. This includes table and column descriptions, synonyms, column type classifications, and global feedback for AI context. This endpoint will reject the request with `409 SEMANTIC_LAYER_ALREADY_EXISTS` if the datamart already has semantic data. Use [PUT](/developer-docs/helpers/api-reference/update-semantic-layer) to modify an existing semantic layer. At least one of `tables` or `feedback` must be provided in the request body. ## Authentication This endpoint requires a **service token** in the Authorization header. Data app API tokens are not permitted and will be rejected with a `403` error. To access your service token: 1. Go to your Databrain dashboard and open **Settings**. 2. Navigate to **Settings**. 3. Find the **Service Tokens** section. 4. Click the **"Generate Token"** button to generate a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the existing datamart to create a semantic layer for. Must match exactly (case-sensitive). * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to get all datamart names * Names are case-sensitive and must match exactly * The datamart must not already have semantic data Array of table objects with semantic metadata. Each table must reference a table that exists in the datamart. * Table `name` must match an existing table in the datamart * Column `name` (when provided) must match an existing column in the respective table * Descriptions are limited to 500 characters * Synonyms are limited to 10 per entity, 100 characters each * Synonyms must be unique (case-insensitive) Table name from the datamart. Must match an existing table. Optional schema name for the table. Human-readable description of the table. Maximum 500 characters. Alternative names for the table. Maximum 10 synonyms, each up to 100 characters. Must be unique (case-insensitive). Additional context for AI query generation. Maximum 1000 characters. Array of column objects with semantic metadata. Column name from the table. Must match an existing column. Human-readable description of the column. Maximum 500 characters. Alternative names for the column. Maximum 10 synonyms, each up to 100 characters. Must be unique (case-insensitive). Additional context for AI query generation. Maximum 1000 characters. Semantic column type classification. Must be one of: `String`, `Long String`, `String (Custom)`, `ENUM`, `Mapper`, `Range`, `Expression`, `Identifier`, `Number`, `JSON`. The column type must be compatible with the column's underlying SQL datatype. For example, `Number` cannot be assigned to a `varchar` column. Additional configuration for the column type. Must match the shape expected for `columnType`: * **`String`**, **`String (Custom)`**, **`ENUM`**, **`Mapper`**: plain object mapping values to descriptions (e.g. `{ "pending": "Not shipped", "shipped": "Sent" }`) * **`Range`**: `{ "lowerLimit": number, "upperLimit": number }` (both must be numbers) * **`Expression`**: string template * **`JSON`**: string (sample JSON) * **`Identifier`**, **`Number`**, **`Long String`**: omit or use `null` (non-null config is rejected) Invalid configs return `400 INVALID_COLUMN_TYPE_CONFIG` with a message describing the required shape. Mark this column as an identifier (e.g., primary key, foreign key). Defaults to `false`. Exclude this column from AI indexing. Defaults to `false`. Global feedback text providing context to the AI about this datamart. Maximum 2000 characters. * Helps guide AI-generated SQL queries * Example: "All monetary amounts are in USD. The fiscal year starts in April." * Can be used alone (without tables) ## Response On success, the response body contains only the datamart name. There is no `error` field in the JSON body when the request succeeds. The name of the datamart (same as the input `datamartName`) on success. ## Examples ```bash cURL - Full Example theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tables": [ { "name": "orders", "description": "Customer purchase orders", "synonyms": ["purchases", "transactions"], "columns": [ { "name": "order_id", "description": "Unique order identifier", "columnType": "Identifier", "isIdentifier": true }, { "name": "status", "description": "Current order status", "synonyms": ["order status", "state"], "columnType": "ENUM" }, { "name": "amount", "description": "Total order amount in USD", "columnType": "Number" } ] } ], "feedback": "This datamart covers e-commerce sales data. All amounts are in USD." }' ``` ```bash cURL - Feedback Only theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "feedback": "This datamart covers e-commerce sales data. Fiscal year starts April 1." }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datamartName: 'sales-analytics', tables: [ { name: 'orders', description: 'Customer purchase orders', synonyms: ['purchases', 'transactions'], columns: [ { name: 'order_id', description: 'Unique order identifier', columnType: 'Identifier', isIdentifier: true }, { name: 'amount', description: 'Total order amount in USD', columnType: 'Number' } ] } ], feedback: 'All amounts are in USD.' }) }); const result = await response.json(); if (result.error) { console.error('Create failed:', result.error.message); } else { console.log('Semantic layer created for:', result.id); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'datamartName': 'sales-analytics', 'tables': [ { 'name': 'orders', 'description': 'Customer purchase orders', 'synonyms': ['purchases', 'transactions'], 'columns': [ { 'name': 'order_id', 'description': 'Unique order identifier', 'columnType': 'Identifier', 'isIdentifier': True }, { 'name': 'amount', 'description': 'Total order amount in USD', 'columnType': 'Number' } ] } ], 'feedback': 'All amounts are in USD.' } ) result = response.json() if result.get('error'): print(f"Create failed: {result['error']['message']}") else: print(f"Semantic layer created for: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { datamartName: 'sales-analytics', tables: [ { name: 'orders', description: 'Customer purchase orders', columns: [ { name: 'order_id', description: 'Unique order identifier', columnType: 'Identifier' }, { name: 'amount', description: 'Total order amount', columnType: 'Number' } ] } ], feedback: 'All amounts are in USD.' }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Created: #{result['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class CreateSemanticLayer { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "datamartName": "sales-analytics", "tables": [ { "name": "orders", "description": "Customer purchase orders", "columns": [ { "name": "order_id", "description": "Unique order identifier", "columnType": "Identifier", "isIdentifier": true }, { "name": "amount", "description": "Total order amount in USD", "columnType": "Number" } ] } ], "feedback": "All amounts are in USD." }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) func main() { body := map[string]interface{}{ "datamartName": "sales-analytics", "tables": []map[string]interface{}{ { "name": "orders", "description": "Customer purchase orders", "columns": []map[string]interface{}{ { "name": "order_id", "description": "Unique order identifier", "columnType": "Identifier", "isIdentifier": true, }, { "name": "amount", "description": "Total order amount in USD", "columnType": "Number", }, }, }, }, "feedback": "All amounts are in USD.", } jsonData, _ := json.Marshal(body) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Semantic layer created") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics', 'tables' => [ [ 'name' => 'orders', 'description' => 'Customer purchase orders', 'columns' => [ [ 'name' => 'order_id', 'description' => 'Unique order identifier', 'columnType' => 'Identifier', 'isIdentifier' => true ], [ 'name' => 'amount', 'description' => 'Total order amount in USD', 'columnType' => 'Number' ] ] ] ], 'feedback' => 'All amounts are in USD.' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); echo "Created: " . $result['id']; ?> ``` ```json 200 - Success theme={"dark"} { "id": "sales-analytics" } ``` ```json 400 - Missing datamartName theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"datamartName\" is required" } } ``` ```json 400 - No Section Provided theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"value\" must contain at least one of [tables, feedback]" } } ``` ```json 400 - Invalid Table theme={"dark"} { "error": { "code": "INVALID_TABLE", "message": "Table 'nonexistent_table' not found in datamart 'sales-analytics'" } } ``` ```json 400 - Invalid Column theme={"dark"} { "error": { "code": "INVALID_COLUMN", "message": "Column 'nonexistent_col' not found in table 'orders'" } } ``` ```json 400 - Incompatible Column Type theme={"dark"} { "error": { "code": "INVALID_COLUMN_TYPE", "message": "Column type 'Number' is not compatible with datatype 'varchar' for column 'status' in table 'orders'" } } ``` ```json 400 - Duplicate Synonyms theme={"dark"} { "error": { "code": "DUPLICATE_SYNONYM", "message": "Duplicate synonyms for table 'orders': purchases" } } ``` ```json 409 - Already Exists theme={"dark"} { "error": { "code": "SEMANTIC_LAYER_ALREADY_EXISTS", "message": "Semantic layer already exists for datamart 'sales-analytics'. Use PUT to update." } } ``` ```json 403 - Data App Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Semantic Layer API requires a service token, not a data app API token" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------- | | `200` | **OK** — Semantic layer created successfully | | `400` | **Bad Request** — Validation failed (see error codes below) | | `401` | **Unauthorized** — Invalid or missing API token | | `403` | **Forbidden** — Data app token used instead of service token | | `409` | **Conflict** — Semantic layer already exists on this datamart | | `500` | **Internal Server Error** — Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ------------------------------- | ----------- | ------------------------------------------------------ | | `INVALID_REQUEST_BODY` | 400 | Missing required fields or validation failure | | `INVALID_DATAMART` | 400 | Datamart not found | | `INVALID_TABLE` | 400 | Table name doesn't exist in the datamart | | `INVALID_COLUMN` | 400 | Column name doesn't exist in the table | | `INVALID_COLUMN_TYPE` | 400 | Column type incompatible with the column's datatype | | `INVALID_COLUMN_TYPE_CONFIG` | 400 | Column type config has wrong shape for the column type | | `DUPLICATE_SYNONYM` | 400 | Duplicate synonyms detected (case-insensitive) | | `SEMANTIC_LAYER_ALREADY_EXISTS` | 409 | Datamart already has semantic data — use PUT to update | | `AUTHENTICATION_ERROR` | 403 | Data app token used instead of service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to confirm the datamart exists and note its exact name. Gather descriptions, synonyms, and column type classifications for your tables: ```json theme={"dark"} { "datamartName": "sales-analytics", "tables": [ { "name": "orders", "description": "Customer purchase orders", "synonyms": ["purchases"], "columns": [ { "name": "order_id", "description": "Unique identifier", "columnType": "Identifier" }, { "name": "amount", "description": "Total in USD", "columnType": "Number" } ] } ], "feedback": "All monetary values are in USD." } ``` ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ ... }' ``` Retrieve the semantic layer to confirm it was created and check the completion score: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ## Next Steps Retrieve and inspect your semantic layer Modify your semantic layer after creation Remove semantic layer metadata Configure the semantic layer in the Databrain UI # Create Service Token (Self-Hosted) Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-service-token POST https://api.usedatabrain.com/api/v2/service-token Create or save a service token for your self-hosted Databrain instance. Available only on self-hosted deployments. Create or register a service token for your self-hosted instance. If no service token exists, a new one is created; if one already exists, it is updated with the provided token value. Service tokens are used for organization-level operations such as managing Data Apps and API tokens. **Self-Hosted Only:** This endpoint is available only on **self-hosted** Databrain instances. It returns an error on cloud (SaaS) deployments. **Authentication Requirement:** This endpoint requires an authenticated admin user (Bearer token from [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt)) and a subscribed account. ## Authentication Use a valid admin session token in the `Authorization` header. Obtain one by calling [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) first. ## Headers Bearer token for an authenticated admin user. ``` Authorization: Bearer ``` Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body The service token value. Must be a valid **UUID** (e.g. RFC 4122). The backend stores this as the service token ID for your company. Generate a UUID (e.g. via `uuidv4`) and send it here. ## Response On success, the API returns **200** with a JSON object: The service token (UUID). Use this value as the Bearer token for service-level API calls (e.g. creating Data App API tokens, export/import dashboard). On error, the API returns a JSON object with `error.code` and `error.message` and an appropriate HTTP status (400 or 500). ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/service-token \ --header 'Authorization: Bearer YOUR_ADMIN_ACCESS_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"token":"550e8400-e29b-41d4-a716-446655440000"}' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/service-token', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ADMIN_ACCESS_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ token: '550e8400-e29b-41d4-a716-446655440000' }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); console.log('Service token:', data.key); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/service-token" headers = { "Authorization": "Bearer YOUR_ADMIN_ACCESS_TOKEN", "Content-Type": "application/json" } payload = {"token": "550e8400-e29b-41d4-a716-446655440000"} response = requests.post(url, headers=headers, json=payload) data = response.json() if data.get("error"): raise Exception(data["error"].get("message", "Request failed")) print("Service token:", data["key"]) ``` ```json Success (200) theme={"dark"} { "key": "550e8400-e29b-41d4-a716-446655440000" } ``` ```json Error (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"token\" is required" } } ``` ```json Error (400) - Invalid UUID theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"token\" must be a valid GUID" } } ``` ```json Error (500) theme={"dark"} { "error": { "code": "SELFHOSTED_APP_ERROR", "message": "This feature is only available for self-hosted instances" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------- | | `200` | **OK** – Service token created or updated; response contains `key` | | `400` | **Bad Request** – Invalid or missing `token` (must be a valid UUID) | | `500` | **Internal Server Error** – Server error or self-hosted-only error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | ----------------------------------------------------------------------------------- | ----------- | | `INVALID_REQUEST_BODY` | Joi validation message (e.g. `"token" is required`, `"token" must be a valid GUID`) | 400 | | `SELFHOSTED_APP_ERROR` | This feature is only available for self-hosted instances | 500 | | `ACCOUNT_NOT_FOUND` | ACCOUNT\_NOT\_FOUND | 500 | | `INTERNAL_SERVER_ERROR` | INTERNAL\_SERVER\_ERROR | 500 | ## Related * [Rotate Service Token](/developer-docs/helpers/api-reference/rotate-service-token) – Rotate the service token with an expiration window * [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account) – Create the first admin account (self-hosted) * [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) – Get an access token for admin APIs # Create Workspace Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/create-workspace POST https://api.usedatabrain.com/api/v2/workspace Create a new workspace with datasource, datamart, multi-datasource, or multi-datamart configuration to organize your analytics environment. Create workspaces to organize your analytics environment by connecting datasources or datamarts. Workspaces serve as containers for dashboards and metrics, providing structured access to your data. Choose a `connectionType` that matches how this workspace will use data. For `DATASOURCE` or `DATAMART`, the corresponding `datasourceName` or `datamartName` must already exist in your organization. For `MULTI_DATASOURCE` or `MULTI_DATAMART`, those name fields are not required in the request body (see `connectionType` below). ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the workspace to create. Must be unique within your organization. * Use descriptive names (e.g., "sales-analytics", "customer-insights") * Alphanumeric characters and spaces are supported * Must be unique within your organization * Cannot be changed after creation (use update API to modify connection) Type of connection for the workspace. Must be one of: `DATASOURCE`, `DATAMART`, `MULTI_DATASOURCE`, or `MULTI_DATAMART`. * **DATASOURCE**: Connect directly to a single datasource * **DATAMART**: Connect to a pre-configured datamart * **MULTI\_DATASOURCE**: Allow connections to multiple datasources within this workspace (`datasourceName` is not required for this type) * **MULTI\_DATAMART**: Allow multiple datamarts in this workspace (`datamartName` is not required for this type; it is required only when `connectionType` is `DATAMART`) Name of the datasource to connect to this workspace. **Required when** `connectionType` is `DATASOURCE`. * Check your datasources list in the DataBrain dashboard * Use the exact name as stored in datasource credentials * Names are case-sensitive Name of the datamart to connect to this workspace. **Required when** `connectionType` is `DATAMART`. * List available datamarts using the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) * Use the exact name as it appears in your datamart configuration * Names are case-sensitive Optional primary LLM name for workspace-level AI features. Must match an existing LLM configured in your organization. Optional list of LLM names available for AI Copilot in this workspace. Every value must match an existing organization LLM name. Optional flag to enable AI-powered metric suggestions in this workspace. Defaults to `false` when omitted. Optional flag to enable AI-generated metric summaries in this workspace. Defaults to `false` when omitted. Summary mode used when metric summaries are enabled. Must be one of: `technicalAndInsightSummary`, `forecastAndTrendAnalysis`, `comparativeAndAnomalyDetection`, `custom`. **Required when** `isEnableMetricSummary` is `true`. Custom summary instruction prompt for AI-generated summaries. **Required when** `summaryType` is `custom`. Optional workspace theme name. Must match an existing theme configured in your organization. ## Response Contains the created workspace information on success. The name of the successfully created workspace. Error object if the request failed, otherwise `null` for successful requests. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Datasource Connection theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "DATASOURCE", "datasourceName": "postgres-main" }' ``` ```bash cURL - Datamart Connection theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Customer Insights", "connectionType": "DATAMART", "datamartName": "customer-data-mart" }' ``` ```bash cURL - Multi-Datasource theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Cross-Platform Analytics", "connectionType": "MULTI_DATASOURCE" }' ``` ```bash cURL - Multi-Datamart theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Multi-Datamart Analytics", "connectionType": "MULTI_DATAMART" }' ``` ```bash cURL - Datamart with AI + Theme Settings theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Executive AI Workspace", "connectionType": "DATAMART", "datamartName": "finance-datamart", "llmName": "gpt-4o", "aiCopilotLlms": ["gpt-4o", "gpt-4.1-mini"], "isEnableMetricSuggestions": true, "isEnableMetricSummary": true, "summaryType": "custom", "customSummaryPrompt": "Summarize KPIs with variance drivers and weekly action items.", "themeName": "Executive Theme" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Sales Analytics', connectionType: 'DATASOURCE', datasourceName: 'postgres-main' }) }); const result = await response.json(); console.log(result); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/workspace', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'name': 'Sales Analytics', 'connectionType': 'DATASOURCE', 'datasourceName': 'postgres-main' } ) result = response.json() print(result) ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/workspace') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { name: 'Sales Analytics', connectionType: 'DATASOURCE', datasourceName: 'postgres-main' }.to_json response = http.request(request) result = JSON.parse(response.body) puts result ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class CreateWorkspace { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "name": "Sales Analytics", "connectionType": "DATASOURCE", "datasourceName": "postgres-main" } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/workspace")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type WorkspaceRequest struct { Name string `json:"name"` ConnectionType string `json:"connectionType"` DatasourceName string `json:"datasourceName,omitempty"` DatamartName string `json:"datamartName,omitempty"` } func main() { reqData := WorkspaceRequest{ Name: "Sales Analytics", ConnectionType: "DATASOURCE", DatasourceName: "postgres-main", } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/workspace", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Workspace created successfully") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Sales Analytics', 'connectionType' => 'DATASOURCE', 'datasourceName' => 'postgres-main' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); echo "Workspace: " . $result['data']['name']; ?> ``` ```json 200 - Success theme={"dark"} { "data": { "name": "Sales Analytics" }, "error": null } ``` ```json 400 - Workspace Already Exists theme={"dark"} { "error": { "code": "WORKSPACE_NAME_ALREADY_EXISTS", "message": "Workspace with the same name already exists" } } ``` ```json 400 - Invalid Datasource theme={"dark"} { "error": { "code": "INVALID_DATASOURCE_NAME", "message": "Invalid datasource name provided" } } ``` ```json 400 - Invalid Datamart theme={"dark"} { "error": { "code": "INVALID_DATAMART_NAME", "message": "Invalid datamart name provided" } } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"connectionType\" is required" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal Server Error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Workspace created successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ------------------------------- | ----------- | ----------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid parameters | | `WORKSPACE_NAME_ALREADY_EXISTS` | 400 | Workspace name already exists | | `INVALID_DATASOURCE_NAME` | 400 | Datasource not found | | `INVALID_DATAMART_NAME` | 400 | Datamart not found | | `INVALID_LLM_NAME` | 400 | Invalid LLM name provided | | `INVALID_AI_COPILOT_LLMS` | 400 | Invalid AI Copilot LLM list | | `INVALID_THEME_NAME` | 400 | Invalid theme name provided | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide Before creating a workspace, ensure you have: * A valid API token from your data app * Either a datasource or datamart already configured * The exact name of your datasource or datamart (case-sensitive) Decide which connection type fits your use case: * **DATASOURCE**: For connecting to a single data source * **DATAMART**: For connecting to a pre-configured datamart with table/column configurations * **MULTI\_DATASOURCE**: For workspaces that need access to multiple datasources * **MULTI\_DATAMART**: For workspaces that support multiple datamarts (same API shape as multi-datasource: only `name` and `connectionType` in the minimal body) Start with DATASOURCE for simple use cases. Use DATAMART when you need structured access with tenancy settings. For multi-datamart setup in the product UI, see [Multi Datamart Workspace](/guides/workspace/multi-datamart-workspace). Make the API call with your chosen configuration: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "My Analytics Workspace", "connectionType": "DATASOURCE", "datasourceName": "postgres-main" }' ``` Successful response returns the workspace name. Save this for use in embed configurations. Reference your workspace in dashboards and metrics: ```javascript theme={"dark"} const embedConfig = { workspaceName: 'My Analytics Workspace', // ... other configuration }; ``` # Data App Embedding APIs Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/data-app-embedding-api Retrieve dashboards and metrics from datapps ### Overview The Databrain API provides endpoints for retrieving dashboards and metrics from data apps in both cloud Databrain and self-hosted Databrain environments. # Datamart API Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/datamart-api APIs to create, delete, and list datamart configurations associated with datasource. ## API Endpoints ### Cloud Databrain Endpoint ```bash theme={"dark"} POST https://api.usedatabrain.com/api/v2/dataApp/datamart/{method_path} ``` ### Self-hosted Databrain Endpoint ```bash theme={"dark"} POST /api/v2/dataApp/datamart/{method_path} ``` Bearer token for API authentication. Format: `Bearer YOUR_API_TOKEN`. # Delete Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-data-app DELETE https://api.usedatabrain.com/api/v2/data-app?name={name} Permanently delete a Data App and all its associated resources. Permanently delete a Data App from your organization. This action removes the Data App along with all associated embed configurations and API tokens. **Destructive Operation:** This action is irreversible. Deleting a Data App will: * Remove all embed configurations associated with this Data App * Invalidate all API tokens for this Data App * Break any embedded dashboards using this Data App's tokens Make sure you have updated your applications before deletion. **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage Data Apps across your organization. ## Endpoint Formats ``` DELETE https://api.usedatabrain.com/api/v2/data-app?name={name} ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` DELETE https://api.usedatabrain.com/api/v2/dataApp?name={name} ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` ## Query Parameters The name of the Data App to delete. This must exactly match the Data App name. * Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to get all Data App names * Check your Databrain dashboard for Data App configurations * The name is case-sensitive ## Response The name of the deleted Data App for confirmation. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app?name=Customer%20Portal%20Analytics' \ --header 'Authorization: Bearer service_token_xyz...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const dataAppName = 'Customer Portal Analytics'; const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app?name=${encodeURIComponent(dataAppName)}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer service_token_xyz...' } }); const data = await response.json(); console.log('Deleted Data App:', data.name); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests from urllib.parse import quote url = "https://api.usedatabrain.com/api/v2/data-app" headers = { "Authorization": "Bearer service_token_xyz..." } params = { "name": "Customer Portal Analytics" } response = requests.delete(url, headers=headers, params=params) data = response.json() print(f"Deleted Data App: {data['name']}") ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DeleteDataApp { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String name = URLEncoder.encode("Customer Portal Analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app?name=%s", name ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer service_token_xyz...") .DELETE() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type DeleteDataAppResponse struct { Name string `json:"name"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app" params := url.Values{} params.Add("name", "Customer Portal Analytics") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("DELETE", fullURL, nil) req.Header.Set("Authorization", "Bearer service_token_xyz...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result DeleteDataAppResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Deleted Data App: %s\n", result.Name) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Customer Portal Analytics' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer service_token_xyz...', 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted Data App: " . $response['name']; ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app') params = { name: 'Customer Portal Analytics' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Delete.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' response = http.request(request) result = JSON.parse(response.body) puts "Deleted Data App: #{result['name']}" ``` ```json 200 - Success theme={"dark"} { "name": "Customer Portal Analytics" } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"name\" is required" } } ``` ```json 400 - Data App Not Found theme={"dark"} { "error": { "code": "DATA_APP_NOT_FOUND", "message": "Data app not found" } } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Data app not found" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Data App deleted successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | ---------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid name parameter | | `DATA_APP_NOT_FOUND` | 400 | Data App with given name not found | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide Before deleting, confirm the Data App exists using the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` Before deletion, update your applications to remove any references to this Data App's API tokens and embed configurations. Make a DELETE request with the Data App name: ```bash theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app?name=My%20Data%20App' \ --header 'Authorization: Bearer service_token_xyz...' ``` Confirm the Data App was deleted by listing Data Apps again: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` ## Best Practices Always verify the Data App exists and check its embeds before deletion Update your applications to remove Data App references before deletion Implement proper error handling for failed deletions Monitor for any broken embedded dashboards after deletion ## Next Steps Create new Data Apps to replace deleted ones View all remaining Data Apps Generate API tokens for your Data Apps View embed configurations for your Data Apps # Delete Datamart Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-datamart DELETE https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName={name} Delete a datamart from your organization. This action cannot be undone. Permanently delete a datamart from your organization. This will remove the datamart and all its associated configurations. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/datamart`. The old endpoint `/api/v2/dataApp/datamart` will be deprecated soon. Please update your integrations to use the new endpoint format. This action is irreversible. Once a datamart is deleted, all its data configurations and associated embed configurations will be permanently removed. ## Endpoint Formats ``` DELETE https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName={name} ``` **Use this endpoint** for all new integrations. Uses REST-ful DELETE method with query parameters. ``` POST https://api.usedatabrain.com/api/v2/dataApp/datamart/delete Content-Type: application/json { "datamartName": "sales-analytics" } ``` This endpoint still works but will be deprecated. Uses POST method with JSON body. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ```bash Authentication theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The name of the datamart to delete. Must match an existing datamart name in your organization. * Use the List Datamarts API to get all datamart names * Check the response from datamart creation * Available in the DataBrain dashboard when viewing datamarts ## Response The name of the deleted datamart for confirmation. Error field, null when successful. ## Examples ```bash cURL theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const datamartName = 'sales-analytics'; const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName=${encodeURIComponent(datamartName)}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Deleted datamart:', data.id); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/datamart" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "datamartName": "sales-analytics" } response = requests.delete(url, headers=headers, params=params) data = response.json() print(f"Deleted datamart: {data['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamart') params = { datamartName: 'sales-analytics' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Delete.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Deleted datamart: #{data['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DataBrainDeleteDatamartAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String datamartName = URLEncoder.encode("sales-analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName=%s", datamartName ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .DELETE() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type DeleteDatamartResponse struct { Id string `json:"id"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/datamart" params := url.Values{} params.Add("datamartName", "sales-analytics") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("DELETE", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var datamartResp DeleteDatamartResponse json.NewDecoder(resp.Body).Decode(&datamartResp) fmt.Printf("Deleted datamart: %s\n", datamartResp.Id) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/datamart?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted datamart: " . $response['id']; ?> ``` ```json Success Response theme={"dark"} { "id": "sales-analytics", "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Datamart not found", "status": 400 } } ``` ## Legacy Endpoint Examples The following examples use the deprecated POST endpoint. These are provided for reference only. **Please use the DELETE endpoint examples above for all new integrations.** ```bash cURL theme={"dark"} curl --request POST \ --url 'https://api.usedatabrain.com/api/v2/dataApp/datamart/delete' \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/dataApp/datamart/delete', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datamartName: 'sales-analytics' }) }); const data = await response.json(); console.log('Deleted datamart:', data.id); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/dataApp/datamart/delete" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } data = { "datamartName": "sales-analytics" } response = requests.post(url, headers=headers, json=data) result = response.json() print(f"Deleted datamart: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/dataApp/datamart/delete') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { datamartName: 'sales-analytics' }.to_json response = http.request(request) data = JSON.parse(response.body) puts "Deleted datamart: #{data['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainDeleteDatamartAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "datamartName": "sales-analytics" }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/dataApp/datamart/delete")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type DeleteDatamartRequest struct { DatamartName string `json:"datamartName"` } type DeleteDatamartResponse struct { Id string `json:"id"` Error interface{} `json:"error"` } func main() { reqData := DeleteDatamartRequest{ DatamartName: "sales-analytics", } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/dataApp/datamart/delete", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var datamartResp DeleteDatamartResponse json.NewDecoder(resp.Body).Decode(&datamartResp) fmt.Printf("Deleted datamart: %s\n", datamartResp.Id) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted datamart: " . $response['id']; ?> ``` ```json Success Response theme={"dark"} { "id": "sales-analytics", "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Datamart not found", "status": 400 } } ``` ## Error Codes **Invalid request body** - Check that datamartName is provided and valid **Unexpected failure** - Internal server error occurred ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------ | | 200 | **OK** - Datamart deleted successfully | | 400 | **Bad Request** - Invalid request parameters or datamart not found | | 401 | **Unauthorized** - Invalid or expired API token | | 500 | **Internal Server Error** - Unexpected server error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | ------------------ | ----------- | | INVALID\_REQUEST\_BODY | Datamart not found | 400 | | INTERNAL\_SERVER\_ERROR | Unexpected failure | 500 | ## Best Practices Before deleting, verify no embed configurations depend on this datamart Consider exporting important configurations before deletion Test deletion process in a non-production environment first Document the deletion for audit and compliance purposes ## Quick Start Guide First, see which datamarts you have available to identify the one to delete: ```bash theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Before deleting, ensure no embed configurations are using this datamart. Use the List Embeds API to verify. Make the deletion request with the exact datamart name as a query parameter: ```bash theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamart?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Update any embed configurations that were using this datamart to reference a different datamart: ```javascript theme={"dark"} // Update embeds that used the deleted datamart await updateEmbed({ embedId: 'embed_123', accessSettings: { datamartName: 'replacement-datamart' } }); ``` **Critical:** This action permanently deletes the datamart and cannot be undone. Ensure all dependent configurations are updated before deletion. ## Next Steps Create a new datamart to replace the deleted one View all remaining datamarts in your organization Create new embed configurations for your remaining datamarts Generate tokens for your updated configurations # Delete Datasource Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-datasource DELETE https://api.usedatabrain.com/api/v2/datasource?datasourceName={name} Delete a datasource from your organization. This action cannot be undone and will remove all associated configurations. Permanently delete a datasource from your organization. This will remove the datasource and all its associated configurations, including cached schemas. This action is irreversible. Once a datasource is deleted, all its configurations and cached schemas will be permanently removed. Ensure no datamarts or other resources depend on this datasource before deletion. ## Endpoint ``` DELETE https://api.usedatabrain.com/api/v2/datasource?datasourceName={name} ``` ## Self-hosted Databrain Endpoint ``` DELETE /api/v2/datasource?datasourceName={name} ``` ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. ```bash Authentication theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/datasource?datasourceName=production-postgres' \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The name of the datasource to delete. Must match exactly as it was created. * Use the [List Datasources API](/developer-docs/helpers/api-reference/list-datasources) to get all datasource names * Check the response from datasource creation * Available in the DataBrain dashboard when viewing datasources ## Response The ID of the deleted datasource for confirmation. Success message confirming the deletion: "Datasource deleted successfully". Error field, null when successful. Not included in successful responses. ## Examples ```bash cURL theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/datasource?datasourceName=production-postgres' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js theme={"dark"} const datasourceName = 'production-postgres'; const response = await fetch( `https://api.usedatabrain.com/api/v2/datasource?datasourceName=${encodeURIComponent(datasourceName)}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); const data = await response.json(); if (data.error) { console.error('Error:', data.error); } else { console.log('Deleted datasource:', data.id); console.log('Message:', data.message); } ``` ```python Python theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/datasource" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "datasourceName": "production-postgres" } response = requests.delete(url, headers=headers, params=params) data = response.json() if data.get('error'): print('Error:', data['error']) else: print(f"Deleted datasource: {data['id']}") print(f"Message: {data['message']}") ``` ```ruby Ruby theme={"dark"} require 'net/http' require 'json' require 'uri' uri = URI('https://api.usedatabrain.com/api/v2/datasource') params = { datasourceName: 'production-postgres' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Delete.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) if data['error'] puts "Error: #{data['error']}" else puts "Deleted datasource: #{data['id']}" puts "Message: #{data['message']}" end ``` ```java Java theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DataBrainDeleteDatasourceAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String datasourceName = URLEncoder.encode("production-postgres", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/datasource?datasourceName=%s", datasourceName ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .DELETE() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type DeleteDatasourceResponse struct { Id string `json:"id"` Message string `json:"message"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/datasource" params := url.Values{} params.Add("datasourceName", "production-postgres") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("DELETE", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var datasourceResp DeleteDatasourceResponse json.NewDecoder(resp.Body).Decode(&datasourceResp) if datasourceResp.Error != nil { fmt.Printf("Error: %v\n", datasourceResp.Error) } else { fmt.Printf("Deleted datasource: %s\n", datasourceResp.Id) fmt.Printf("Message: %s\n", datasourceResp.Message) } } ``` ```php PHP theme={"dark"} 'production-postgres' ]); $url = 'https://api.usedatabrain.com/api/v2/datasource?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); if (isset($response['error'])) { echo "Error: " . json_encode($response['error']); } else { echo "Deleted datasource: " . $response['id'] . "\n"; echo "Message: " . $response['message']; } ?> ``` ```json Success Response theme={"dark"} { "id": "uuid-of-deleted-datasource", "message": "Datasource deleted successfully" } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid datasource name", "status": 400 } } ``` ```json Error Response (400) - Datasource Not Found theme={"dark"} { "error": { "code": "DATASOURCE_NAME_ERROR", "message": "Invalid datasource name", "status": 400 } } ``` ```json Error Response (400) - Datasource In Use theme={"dark"} { "error": { "code": "DATASOURCE_IN_USE", "message": "Cannot delete datasource as it is being used by other resources", "status": 400 } } ``` ```json Error Response (401) theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "AUTHENTICATION_ERROR", "status": 401 } } ``` ## Error Codes | Error Code | HTTP Status | Description | | ----------------------- | ----------- | ------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid datasourceName parameter | | `DATASOURCE_NAME_ERROR` | 400 | Datasource not found | | `DATASOURCE_IN_USE` | 400 | Datasource is being used by other resources | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error occurred | ## Next Steps Create a new datasource to replace the deleted one View all remaining datasources in your organization Update datasource credentials instead of deleting Create datamarts using your remaining datasources # Delete an Embed Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-embed DELETE https://api.usedatabrain.com/api/v2/data-app/embeds?embedId={id} Delete an embed from your data app. This action cannot be undone. Permanently delete an embed from your data app. This will remove the embed and invalidate any associated guest tokens. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/embeds`. The old endpoint `/api/v2/dataApp/embeds` will be deprecated soon. Please update your integrations to use the new endpoint format. This action is irreversible. Once an embed configuration is deleted, all associated guest tokens will become invalid and embedded dashboards will stop working. ## Endpoint Formats ``` DELETE https://api.usedatabrain.com/api/v2/data-app/embeds?embedId={id} ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/data-app/embeds?embedId={id} Content-Type: application/json { "embedId": "embed_abc123def456" } ``` This endpoint still works but will be deprecated. Uses POST method with JSON body. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The unique identifier of the embed configuration to delete. Get this from the create embed response or list embeds API. * Use the List All Embeds API to get embed IDs * Check the response from embed creation * Available in the DataBrain dashboard when viewing embed configurations Optional parameter to also delete the associated dashboard along with the embed configuration. Set to `"true"` to enable dashboard deletion. **Destructive Operation:** When set to `"true"`, this will permanently delete the dashboard associated with this embed. This action cannot be undone. **When dashboard deletion is allowed:** * Dashboard was created via API. * Dashboard is only referenced by this single embed * Embed and dashboard both belong to your organization **Params:** * `isDeleteDashboard=true` - Delete both embed and dashboard * `isDeleteDashboard=false` or omitted - Delete only embed configuration ## Response The ID of the deleted embed configuration for confirmation. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Delete Embed Only theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL - Delete Embed and Dashboard theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456&isDeleteDashboard=true' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js - Delete Embed Only icon="fa-brands fa-node-js" theme={"dark"} const embedId = 'embed_abc123def456'; const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=${encodeURIComponent(embedId)}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Deleted embed:', data.id); ``` ```javascript Node.js - Delete Embed and Dashboard icon="fa-brands fa-node-js" theme={"dark"} const embedId = 'embed_abc123def456'; const isDeleteDashboard = true; const url = new URL('https://api.usedatabrain.com/api/v2/data-app/embeds'); url.searchParams.append('embedId', embedId); url.searchParams.append('isDeleteDashboard', isDeleteDashboard.toString()); const response = await fetch(url, { method: 'DELETE', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Deleted embed and dashboard:', data.id); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/embeds" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "embedId": "embed_abc123def456" } response = requests.delete(url, headers=headers, params=params) data = response.json() print(f"Deleted embed: {data['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/embeds') params = { embedId: 'embed_abc123def456' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Delete.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Deleted embed: #{data['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DataBrainDeleteEmbedAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String embedId = URLEncoder.encode("embed_abc123def456", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=%s", embedId ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .DELETE() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type DeleteEmbedResponse struct { Id string `json:"id"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/embeds" params := url.Values{} params.Add("embedId", "embed_abc123def456") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("DELETE", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var embedResp DeleteEmbedResponse json.NewDecoder(resp.Body).Decode(&embedResp) fmt.Printf("Deleted embed: %s\n", embedResp.Id) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'embed_abc123def456' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/embeds?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted embed: " . $response['id']; ?> ``` ```json Success Response theme={"dark"} { "id": "embed_abc123def456" } ``` ```json Error - Embed Not Found theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Embed not found" } } ``` ```json Error - Internal Dashboard Cannot Be Deleted theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Deletion blocked: internal dashboards can't be removed." } } ``` ```json Error - Dashboard Referenced by Multiple Embeds theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Deletion blocked: this dashboard is referenced by multiple embeds." } } ``` ```json Error - Invalid API Key theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ## Legacy Endpoint Examples The following examples use the deprecated POST endpoint. These are provided for reference only. **Please use the DELETE endpoint examples above for all new integrations.** ```bash cURL theme={"dark"} curl --request POST \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456' \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId: 'embed_abc123def456' }) }); const data = await response.json(); console.log('Deleted embed:', data.id); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } data = { "embedId": "embed_abc123def456" } response = requests.post(url, headers=headers, json=data) result = response.json() print(f"Deleted embed: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { embedId: 'embed_abc123def456' }.to_json response = http.request(request) data = JSON.parse(response.body) puts "Deleted embed: #{data['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainDeleteEmbedAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "embedId": "embed_abc123def456" }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type DeleteEmbedRequest struct { EmbedId string `json:"embedId"` } type DeleteEmbedResponse struct { Id string `json:"id"` Error interface{} `json:"error"` } func main() { reqData := DeleteEmbedRequest{ EmbedId: "embed_abc123def456", } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/embeds?embedId=embed_abc123def456", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var embedResp DeleteEmbedResponse json.NewDecoder(resp.Body).Decode(&embedResp) fmt.Printf("Deleted embed: %s\n", embedResp.Id) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'embed_abc123def456' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted embed: " . $response['id']; ?> ``` ```json Success Response theme={"dark"} { "id": "embed_abc123def456", "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Embed not found", "status": 400 } } ``` ## Error Codes **Invalid request body** - Check that embedId is provided and valid **Missing or invalid data app** - Check your API key and data app configuration **Unexpected failure** - Internal server error occurred ## HTTP Status Code Summary | Status Code | Description | | ----------- | --------------------------------------------------------------- | | 200 | **OK** - Embed deleted successfully | | 400 | **Bad Request** - Invalid request parameters or embed not found | | 500 | **Internal Server Error** - Unexpected server error | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ---------------------------------------------- | | `INVALID_REQUEST_BODY` | 500 | Embed not found | | `INVALID_REQUEST_BODY` | 500 | Internal dashboards can't be removed | | `INVALID_REQUEST_BODY` | 500 | Dashboard is referenced by multiple embeds | | `INVALID_DATA_APP_API_KEY` | 400 | invalid or expired API KEY, data app not found | ## Usage Examples ### Basic Deletion ```javascript theme={"dark"} // Delete an embed configuration const result = await deleteEmbed({ embedId: 'embed_123' }); console.log(`Deleted embed: ${result.id}`); ``` ### Batch Deletion ```javascript theme={"dark"} // Delete multiple embed configurations const embedIds = ['embed_1', 'embed_2', 'embed_3']; for (const embedId of embedIds) { try { const result = await deleteEmbed({ embedId }); console.log(`Deleted embed: ${result.id}`); } catch (error) { console.error(`Failed to delete ${embedId}:`, error.message); } } ``` ### Safe Deletion with Verification ```javascript theme={"dark"} // Verify embed exists before deletion const embeds = await listEmbeds(); const embedToDelete = embeds.data.find(e => e.embedId === 'embed_123'); if (embedToDelete) { const result = await deleteEmbed({ embedId: embedToDelete.embedId }); console.log(`Successfully deleted: ${result.id}`); } else { console.log('Embed not found'); } ``` ## Best Practices Always verify the embed exists before attempting deletion Implement proper error handling for failed deletions Update your integration documentation after deletions Monitor for any broken embedded dashboards after deletion **Important:** Deleting an embed configuration will invalidate all guest tokens associated with it and break any embedded dashboards using this configuration. Ensure you have updated your application before deletion. ## Next Steps Create new embed configurations to replace deleted ones View all remaining embed configurations Modify existing embed configurations instead of deleting Generate new tokens for your updated configurations # Delete Semantic Layer Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-semantic-layer DELETE https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName={name} Delete the semantic layer from a datamart, removing all descriptions, synonyms, column types, and feedback. Permanently remove all semantic layer metadata from a datamart. This clears table descriptions, column metadata (descriptions, synonyms, column types, configs), and feedback. The underlying datamart structure (tables, columns) remains intact. This action cannot be undone. All semantic metadata — descriptions, synonyms, column types, and feedback — will be permanently removed. The datamart itself is not deleted. Only the semantic layer enrichments are removed. You can recreate the semantic layer using the [POST endpoint](/developer-docs/helpers/api-reference/create-semantic-layer). ## Authentication This endpoint requires a **service token** in the Authorization header. Data app API tokens are not permitted and will be rejected with a `403` error. To access your service token: 1. Go to your Databrain dashboard and open **Settings**. 2. Navigate to **Settings**. 3. Find the **Service Tokens** section. 4. Click the **"Generate Token"** button to generate a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The name of the datamart whose semantic layer you want to delete. Must match an existing datamart that has semantic data. * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to get all datamart names * Use the [Get Semantic Layer API](/developer-docs/helpers/api-reference/get-semantic-layer) to confirm semantic data exists ## Response On success, the response body contains only the datamart name. There is no `error` field in the JSON body when the request succeeds. The name of the datamart whose semantic layer was deleted. ## Examples ```bash cURL theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const datamartName = 'sales-analytics'; const response = await fetch( `https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=${encodeURIComponent(datamartName)}`, { method: 'DELETE', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); const result = await response.json(); if (result.error) { console.error('Delete failed:', result.error.message); } else { console.log('Semantic layer deleted for:', result.id); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.delete( 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', headers={ 'Authorization': 'Bearer dbn_live_abc123...' }, params={ 'datamartName': 'sales-analytics' } ) result = response.json() if result.get('error'): print(f"Delete failed: {result['error']['message']}") else: print(f"Semantic layer deleted for: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer') params = { datamartName: 'sales-analytics' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Delete.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) result = JSON.parse(response.body) puts "Deleted: #{result['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DeleteSemanticLayer { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String datamartName = URLEncoder.encode("sales-analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=%s", datamartName ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .DELETE() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer" params := url.Values{} params.Add("datamartName", "sales-analytics") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("DELETE", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Deleted: %v\n", result["id"]) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'DELETE' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Deleted: " . $response['id']; ?> ``` ```json 200 - Success theme={"dark"} { "id": "sales-analytics" } ``` ```json 400 - Missing datamartName theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "datamartName query parameter is required" } } ``` ```json 400 - Datamart Not Found theme={"dark"} { "error": { "code": "INVALID_DATAMART", "message": "Datamart 'nonexistent' not found" } } ``` ```json 404 - No Semantic Layer theme={"dark"} { "error": { "code": "SEMANTIC_LAYER_NOT_FOUND", "message": "No semantic layer found for datamart 'sales-analytics'." } } ``` ```json 403 - Data App Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Semantic Layer API requires a service token, not a data app API token" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------ | | `200` | **OK** — Semantic layer deleted successfully | | `400` | **Bad Request** — Missing datamartName or datamart not found | | `401` | **Unauthorized** — Invalid or missing API token | | `403` | **Forbidden** — Data app token used instead of service token | | `404` | **Not Found** — No semantic layer exists for this datamart | | `500` | **Internal Server Error** — Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | datamartName query parameter is missing | | `INVALID_DATAMART` | 400 | Datamart not found | | `SEMANTIC_LAYER_NOT_FOUND` | 404 | No semantic layer exists for this datamart | | `AUTHENTICATION_ERROR` | 403 | Data app token used instead of service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Best Practices Use the GET endpoint to save a copy of the semantic layer before deleting AI chat mode relies on the semantic layer — verify impact before deleting ## Quick Start Guide Retrieve and save the current semantic layer data: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' \ -o semantic-layer-backup.json ``` ```bash theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Retrieve the datamart again to confirm the semantic layer was cleared: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` The response should show `null` descriptions, empty synonyms, and a completion score of `0`. ## Next Steps Recreate the semantic layer with fresh metadata Verify the deletion Configure the semantic layer in the Databrain UI View your datamarts # Delete Workspace Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/delete-workspace DELETE https://api.usedatabrain.com/api/v2/workspace?name={name} Permanently delete a workspace from your organization by name. Permanently delete a workspace. The workspace is identified by the **`name`** query parameter. The payload is validated with **`name`**: required string (`Joi.string().required()`). This action is irreversible. Ensure no dashboards, metrics, or embeds still depend on this workspace before deleting it. ## Endpoint ``` DELETE https://api.usedatabrain.com/api/v2/workspace?name={name} ``` ## Self-hosted Databrain Endpoint ``` DELETE /api/v2/workspace?name={name} ``` ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ```bash Authentication theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/workspace?name=sales-analytics' \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters Workspace name to delete. Must match an existing workspace in your organization (case-sensitive, same string as returned by list/create). If `name` is omitted, validation fails with `INVALID_REQUEST_BODY` and the Joi validation message (for example `"name" is required`). * Use the [List Workspaces API](/developer-docs/helpers/api-reference/list-workspaces) to list workspace names * Use the same value as in [Create Workspace](/developer-docs/helpers/api-reference/create-workspace) / [Update Workspace](/developer-docs/helpers/api-reference/update-workspace) ## Response On success, the API returns a top-level **`data`** object (same shape as other `/api/v2/workspace` handlers). Set to the workspace **`name`** that was deleted (string echoed from the query parameter). Success message: `Workspace deleted successfully`. On success, `error` is omitted or null. On failure, contains `code` and `message` (see examples below). ## Examples ```bash cURL theme={"dark"} curl --request DELETE \ --url 'https://api.usedatabrain.com/api/v2/workspace?name=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const workspaceName = 'sales-analytics'; const response = await fetch( `https://api.usedatabrain.com/api/v2/workspace?name=${encodeURIComponent(workspaceName)}`, { method: 'DELETE', headers: { Authorization: 'Bearer dbn_live_abc123...', }, } ); const result = await response.json(); if (result.error) { console.error('Error:', result.error); } else { console.log('Deleted workspace:', result.data); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/workspace" headers = {"Authorization": "Bearer dbn_live_abc123..."} params = {"name": "sales-analytics"} response = requests.delete(url, headers=headers, params=params) result = response.json() if result.get("error"): print("Error:", result["error"]) else: print("Deleted workspace:", result.get("data")) ``` ```json 200 - Success theme={"dark"} { "data": { "id": "sales-analytics", "message": "Workspace deleted successfully" } } ``` ```json 400 - Missing or invalid API key (middleware) theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is not provided or Invalid!" } } ``` ```json 400 - Invalid request body (Joi) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"name\" is required" } } ``` ```json 400 - Workspace not found theme={"dark"} { "error": { "code": "WORKSPACE_ID_ERROR", "message": "invalid workspace name, workspace name not found" } } ``` ```json 401 - Invalid or expired API key (middleware) theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is invalid or expired!" } } ``` ```json 500 - Internal server error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ----------------------------------------------------------------------------------------------------- | | `200` | **OK** — Workspace deleted successfully | | `400` | **Bad Request** — Missing/invalid API key (middleware), Joi validation failed, or workspace not found | | `401` | **Unauthorized** — Invalid/expired token or missing required scopes (middleware) | | `500` | **Internal Server Error** — Delete mutation failed or unexpected error | ## Possible Errors | Error code | HTTP status | When it occurs | | ----------------------- | ----------- | ---------------------------------------------------------------- | | `AUTHENTICATION_ERROR` | 400 | Authorization missing or malformed (`isPrivateApp` middleware) | | `INVALID_REQUEST_BODY` | 400 | `deleteWorkspaceSchema` validation failed (e.g. missing `name`) | | `WORKSPACE_ID_ERROR` | 400 | No workspace with that `name` for your company | | `AUTHENTICATION_ERROR` | 401 | Service token invalid, expired, or missing required scopes | | `INTERNAL_SERVER_ERROR` | 500 | Delete mutation returned no row, GraphQL error, or handler catch | ## Next Steps List remaining workspaces in your organization Create a new workspace after deletion Update workspace settings instead of deleting # Embed Data App API (CRUD) Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/embed-data-app-crud APIs to create, update, delete, and list embed configurations associated with dashboards or metrics in data app ## API Endpoints ### Cloud Databrain Endpoint ```bash theme={"dark"} POST https://api.usedatabrain.com/api/v2/dataApp/embed/{method_path} ``` ### Self-hosted Databrain Endpoint ```bash theme={"dark"} POST /api/v2/dataApp/embed/{method_path} ``` Bearer token for API authentication. Format: `Bearer YOUR_API_TOKEN`. # Embedding APIs Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/embedding-apis Retrieve dashboards and metrics from workspaces ### Overview The Databrain API provides endpoints for retrieving dashboards and metrics from workspaces in both Cloud Databrain and self-hosted Databrain environments. To use the API, you need to pass a workspaceName along with other optional parameters. **First-time flow:** Create an embed ([Create Embed](/developer-docs/helpers/api-reference/create-embed) or [Create Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed)), list embeds ([List Embeds](/developer-docs/helpers/api-reference/list-embed)) to verify metadata configurations and identify the created embed, then call [Update Workspace Dashboards](/developer-docs/helpers/api-reference/update-workspace-dashboards) to apply filter mapping changes using the embed id listed in metadata. # Export Dashboard Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/export-dashboard POST https://api.usedatabrain.com/api/v2/data-app/export-dashboard Export a dashboard from a workspace as a JSON file for backup, migration, or import into another workspace. Export a dashboard and its configuration (layout, metrics, filters) from a workspace. The response is a JSON file download that can be used with the [Import Dashboard API](/developer-docs/helpers/api-reference/import-dashboard) or the UI import flow. **Authentication Requirement:** This endpoint requires a **service token** (company-level), not a data app API key. Service tokens have elevated permissions. Use the token that has access to the workspace and dashboard. ## Authentication Use your service token in the `Authorization` header. See [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) for how to obtain a service token. ```bash Authentication theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/export-dashboard \ --header 'Authorization: Bearer YOUR_SERVICE_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"dashboardId":"your-dashboard-id","workspaceName":"Your Workspace"}' ``` ## Headers Bearer token for API authentication. Use your **service token** (company-level). ``` Authorization: Bearer dbn_live_... ``` Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body The dashboard ID to export. This is the external dashboard ID (e.g. from [Fetch Dashboards by Data App](/developer-docs/helpers/api-reference/fetch-dashboards-by-datapp) or the dashboard list in the UI). The name of the workspace that contains the dashboard. Must match the workspace name exactly. ## Response On success, the API returns **200** with: * **Content-Type:** `application/json` * **Content-Disposition:** `attachment; filename="dashboard-{dashboardId}.json"` The response body is a JSON object with this structure: Metadata about the export. ISO 8601 timestamp when the export was performed. The workspace name the dashboard was exported from. The dashboard ID that was exported. The dashboard configuration and content (layout, metrics, filters, etc.). Structure matches what the import API expects as `importDashboardData`. On error, the API returns a JSON error object (e.g. 400 or 500) with `error.code` and `error.message`. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url 'https://api.usedatabrain.com/api/v2/data-app/export-dashboard' \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' \ --data '{"dashboardId":"sales-dashboard-1","workspaceName":"Sales Workspace"}' \ --output dashboard-sales-dashboard-1.json ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/export-dashboard', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ dashboardId: 'sales-dashboard-1', workspaceName: 'Sales Workspace' }) }); if (!response.ok) { const err = await response.json(); throw new Error(err.error?.message || 'Export failed'); } const blob = await response.blob(); // Save or process the JSON file const text = await blob.text(); const exported = JSON.parse(text); console.log('Exported at:', exported._meta?.exportedAt); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/export-dashboard" headers = { "Authorization": "Bearer dbn_live_...", "Content-Type": "application/json" } payload = { "dashboardId": "sales-dashboard-1", "workspaceName": "Sales Workspace" } response = requests.post(url, headers=headers, json=payload) if not response.ok: raise Exception(response.json().get("error", {}).get("message", "Export failed")) with open("dashboard-sales-dashboard-1.json", "w") as f: f.write(response.text) ``` ```json Success (response body is the downloaded JSON) theme={"dark"} { "_meta": { "exportedAt": "2025-02-13T10:00:00.000Z", "workspaceName": "Sales Workspace", "dashboardId": "sales-dashboard-1" }, "data": { "layout": [...], "filters": [...], ... } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"dashboardId\" is required" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "AUTH_ERROR", "message": "Invalid Service Token" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "DATA_APP_NOT_FOUND", "message": "Data app not found" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------------------------------------ | | `200` | **OK** – Dashboard exported successfully; response is a JSON file (attachment) | | `400` | **Bad Request** – Invalid or missing parameters, invalid token, or dashboard/workspace not found | | `500` | **Internal Server Error** – Server error during export | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | --------------------------------------------------------- | ----------- | | `INVALID_REQUEST_BODY` | Joi validation message (e.g. `"dashboardId" is required`) | 400 | | `AUTH_ERROR` | Invalid Service Token | 400 | | `DATA_APP_NOT_FOUND` | Data app not found | 400 | | `INTERNAL_SERVER_ERROR` | Server error message | 500 | ## Related * [Import Dashboard](/developer-docs/helpers/api-reference/import-dashboard) – Import a previously exported dashboard into a workspace * [Fetch Dashboards by Data App](/developer-docs/helpers/api-reference/fetch-dashboards-by-datapp) – List dashboards to get `dashboardId` values * [Import/Export Dashboard (UI)](/guides/dashboards/import-export-dashboard) – UI guide for import/export # Export Embedded Dashboard Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/export-embed GET https://api.usedatabrain.com/api/v2/data-app/embeds/export?embedId={embed_abc123} Export the dashboard and configuration behind a data app embed using a data app API token. Export the dashboard and its configuration (layout, metrics, filters) associated with a specific embed configuration. This endpoint is useful when you want to: * Clone an embedded dashboard into another workspace or client * Back up the configuration behind an embed * Feed the exported configuration into the **Create Empty Dashboard Embed** API via `importDashboardData` **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/embeds/export`. The old endpoint `/api/v2/dataApp/embeds/export` will be deprecated soon. Please update your integrations to use the new endpoint format. ## Authentication All API requests must include your **data app API token** in the `Authorization` header. This is the same token you use for other data app embedding APIs. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request GET \ --url "https://api.usedatabrain.com/api/v2/data-app/embeds/export?embedId=embed_abc123" \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ## Headers Bearer token for API authentication. Use your **data app API token**. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The embed configuration ID to export. This identifies which embedded dashboard's configuration should be exported. * Created when you configure an embed via the [Create Embed API](/developer-docs/helpers/api-reference/create-embed) or [Create Empty Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed) * Retrieved via the [List Embeds API](/developer-docs/helpers/api-reference/list-embed) * Available in your DataBrain dashboard embed settings ## Response On success, the API returns **200** with: * **Content-Type:** `application/json` * **Content-Disposition:** `attachment; filename="dashboard-{embedId}.json"` The response body is a JSON object with this structure: Metadata about the export and the embed configuration. ISO 8601 timestamp when the export was performed. The embed ID that was exported. Human-readable name of the embed configuration. Type of embed configuration: typically `"dashboard"` or `"metric"`. External dashboard ID associated with this embed. This is the dashboard that the export is based on. Access settings associated with the embed, including flags like `isAllowEmailReports`, `isAllowManageMetrics`, and other permissions. The dashboard configuration and content (layout, metrics, filters, etc.). Structure matches what the Import Dashboard API expects as `importDashboardData`, and what the **Create Empty Dashboard Embed** API expects when you pass `importDashboardData` in the request body. On error, the API returns a JSON error object with `error.code`, `error.message`, and `error.status`. Possible errors include: * `INVALID_REQUEST_BODY` – Request validation failed (for example, missing or invalid `embedId`) * `INVALID_DATA_APP_API_KEY` – Invalid or missing data app API token * `EMBED_PARAM_ERROR` – Invalid or unknown embed ID for the current data app * `INVALID_EMBED_ID` – Embed not found * `INTERNAL_SERVER_ERROR` – Unexpected server error ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds/export?embedId=embed_abc123' \ --header 'Authorization: Bearer dbn_live_abc123...' \ --output dashboard-embed_abc123.json ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const params = new URLSearchParams({ embedId: 'embed_abc123' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/embeds/export?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...', }, }); if (!response.ok) { const err = await response.json(); throw new Error(err.error?.message || 'Export failed'); } const text = await response.text(); const exported = JSON.parse(text); console.log('Exported at:', exported._meta?.exportedAt); console.log('Embed dashboard id:', exported._meta?.dashboardId); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/embeds/export" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "embedId": "embed_abc123" } response = requests.get(url, headers=headers, params=params) if not response.ok: err = response.json().get("error", {}) raise Exception(err.get("message", "Export failed")) exported = response.json() print("Exported at:", exported["_meta"]["exportedAt"]) print("Dashboard ID:", exported["_meta"]["dashboardId"]) ``` ```json Success (truncated) theme={"dark"} { "_meta": { "exportedAt": "2026-03-11T10:00:00.000Z", "embedId": "embed_abc123", "name": "Customer Analytics Embed", "embedType": "dashboard", "dashboardId": "sales-dashboard-1", "embedDataAppAccessSetting": { "isAllowEmailReports": true, "isAllowManageMetrics": true, "isAllowCreateDashboardView": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "metricCreationMode": "DRAG_DROP", "isIncrementalJoin": true } }, "data": { "layout": [...], "filters": [...], "metrics": [...], "...": "additional dashboard configuration" } } ``` ```json Error Response (400 - invalid embedId) theme={"dark"} { "error": { "code": "EMBED_PARAM_ERROR", "message": "Invalid default embed id", "status": 400 } } ``` ```json Error Response (401 - invalid data app token) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Invalid Data App API Key", "status": 401 } } ``` ## Common Workflow: Clone an Embed Dashboard 1. **Export the embed dashboard configuration** Use this endpoint to export the configuration for an existing embed: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds/export?embedId=embed_abc123' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` 2. **Create a new client dashboard using `importDashboardData`** Pass the exported `data` payload into the [Create Empty Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed) API: ```json theme={"dark"} { "dashboardId": "client-acme-analytics", "clientId": "acme-corp-123", "workspaceName": "analytics-workspace", "name": "ACME Analytics Dashboard", "isRenameDashboard": true, "importDashboardData": exported.data, "accessSettings": { "datamartName": "customer-analytics", "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowCreateDashboardView": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": false, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "metricCreationMode": "DRAG_DROP" } } ``` This flow lets you reuse an existing embedded dashboard as a starting point for new client dashboards while keeping the configuration in sync. # Fetch Dashboards by Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/fetch-dashboards-by-datapp GET https://api.usedatabrain.com/api/v2/data-app/dashboards Retrieve a list of dashboards available in your data app with optional filtering and pagination. Fetch all dashboards associated with your data app. This endpoint allows you to discover available dashboards for embedding or integration purposes, with support for filtering by dashboard names and pagination. **API Method Migration Notice:** We're transitioning from POST to GET for this endpoint. The new GET method is recommended for all new integrations. The POST method will be deprecated soon. This endpoint returns dashboards that have been configured for your data app. Use the dashboard information to create embed configurations or for display purposes. ## API Methods ``` GET https://api.usedatabrain.com/api/v2/data-app/dashboards ``` **Use this method** for all new integrations. This is the recommended approach with query parameters. ``` POST https://api.usedatabrain.com/api/v2/data-app/dashboards ``` This method still works but will be deprecated. Please migrate to the GET method. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Required only for POST method. Must be set to `application/json`. ``` Content-Type: application/json ``` ## Query Parameters Enable pagination to limit the number of results returned. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number for pagination (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). Comma-separated list of dashboard names to filter by. Only dashboards with matching names will be returned. **Example:** `"Sales Dashboard,Marketing Analytics,Customer Insights"` ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/dashboards?isPagination=true&pageNumber=1&dashboardNames=Sales%20Dashboard,Marketing%20Analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const params = new URLSearchParams({ isPagination: 'true', pageNumber: '1', dashboardNames: 'Sales Dashboard,Marketing Analytics' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/dashboards?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Dashboards:', data.data); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/dashboards" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "isPagination": "true", "pageNumber": "1", "dashboardNames": "Sales Dashboard,Marketing Analytics" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Dashboards: {data['data']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/dashboards') params = { isPagination: 'true', pageNumber: '1', dashboardNames: 'Sales Dashboard,Marketing Analytics' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Dashboards: #{data['data']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class DataBrainDashboardsAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String dashboardNames = URLEncoder.encode("Sales Dashboard,Marketing Analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/dashboards?isPagination=true&pageNumber=1&dashboardNames=%s", dashboardNames ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type Dashboard struct { Name string `json:"name"` ExternalDashboardID string `json:"externalDashboardId"` EmbedID string `json:"embedId"` } type DashboardResponse struct { Data []Dashboard `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/dashboards" params := url.Values{} params.Add("isPagination", "true") params.Add("pageNumber", "1") params.Add("dashboardNames", "Sales Dashboard,Marketing Analytics") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var dashboardResp DashboardResponse json.NewDecoder(resp.Body).Decode(&dashboardResp) fmt.Printf("Dashboards: %+v\n", dashboardResp.Data) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'true', 'pageNumber' => '1', 'dashboardNames' => 'Sales Dashboard,Marketing Analytics' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/dashboards?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Dashboards: " . print_r($response['data'], true); ?> ``` ```json Success Response theme={"dark"} { "data": [ { "name": "Sales Dashboard", "externalDashboardId": "sales_dash_123", "embedId": "embed_abc123" }, { "name": "Marketing Analytics", "externalDashboardId": "marketing_dash_456", "embedId": "embed_def456" } ] } ``` ```json Empty Results Response theme={"dark"} { "data": [] } ``` ```json Error Response (401) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Invalid or missing Data App API Key" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Required fields missing or wrong type" } } ``` ## Legacy Endpoint Examples The following examples use the deprecated POST method. These are provided for reference only. **Please use the GET method examples above for all new integrations.** ## POST Method (Legacy - Being Deprecated) ### Request Body (POST) Enable pagination to limit the number of results returned. When enabled, use `pageNumber` to navigate through pages. Page number for pagination (1-based). Only used when `isPagination` is `true`. Each page returns up to 10 dashboards. Optional filters to narrow down the dashboard results. Array of specific dashboard names to filter by. Only dashboards with matching names will be returned. ```json Example theme={"dark"} ["Sales Dashboard", "Marketing Analytics", "Customer Insights"] ``` ### POST Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "isPagination": true, "pageNumber": 1, "filters": { "dashboardNames": ["Sales Dashboard", "Marketing Analytics"] } }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/dashboards', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ isPagination: true, pageNumber: 1, filters: { dashboardNames: ['Sales Dashboard', 'Marketing Analytics'] } }) }); const data = await response.json(); console.log('Dashboards:', data.data); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests import json url = "https://api.usedatabrain.com/api/v2/data-app/dashboards" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } payload = { "isPagination": True, "pageNumber": 1, "filters": { "dashboardNames": ["Sales Dashboard", "Marketing Analytics"] } } response = requests.post(url, headers=headers, data=json.dumps(payload)) data = response.json() print(f"Dashboards: {data['data']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/dashboards') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { isPagination: true, pageNumber: 1, filters: { dashboardNames: ['Sales Dashboard', 'Marketing Analytics'] } }.to_json response = http.request(request) data = JSON.parse(response.body) puts "Dashboards: #{data['data']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.HashMap; import java.util.List; import java.util.Arrays; public class DataBrainDashboardsAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); ObjectMapper mapper = new ObjectMapper(); Map filters = new HashMap<>(); filters.put("dashboardNames", Arrays.asList("Sales Dashboard", "Marketing Analytics")); Map requestBody = new HashMap<>(); requestBody.put("isPagination", true); requestBody.put("pageNumber", 1); requestBody.put("filters", filters); String jsonBody = mapper.writeValueAsString(requestBody); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/dashboards")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type DashboardFilters struct { DashboardNames []string `json:"dashboardNames"` } type DashboardRequest struct { IsPagination bool `json:"isPagination"` PageNumber int `json:"pageNumber"` Filters DashboardFilters `json:"filters"` } type Dashboard struct { Name string `json:"name"` ExternalDashboardID string `json:"externalDashboardId"` EmbedID string `json:"embedId"` } type DashboardResponse struct { Data []Dashboard `json:"data"` Error interface{} `json:"error"` } func main() { reqBody := DashboardRequest{ IsPagination: true, PageNumber: 1, Filters: DashboardFilters{ DashboardNames: []string{"Sales Dashboard", "Marketing Analytics"}, }, } jsonData, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/dashboards", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var dashboardResp DashboardResponse json.NewDecoder(resp.Body).Decode(&dashboardResp) fmt.Printf("Dashboards: %+v\n", dashboardResp.Data) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} true, 'pageNumber' => 1, 'filters' => [ 'dashboardNames' => ['Sales Dashboard', 'Marketing Analytics'] ] ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Dashboards: " . print_r($response['data'], true); ?> ``` ## Response (Success 200) Array of dashboard objects available in your data app. Display name of the dashboard. Unique identifier for the dashboard that can be used in embed configurations. Embed ID associated with this dashboard, if available. ## Error Response Error object returned only when the request fails. Not included in successful responses. Error code identifier. Human-readable error message. ## Error Codes **Invalid or missing Data App API Key** - Check your API key and ensure it's valid for your data app **Invalid request parameters** - Verify that your request body contains valid field types ## HTTP Status Code Summary | Status Code | Description | | ----------- | --------------------------------------------------------------- | | `200` | **OK** - Dashboards retrieved successfully | | `400` | **Bad Request** - Invalid request parameters or missing API key | | `401` | **Unauthorized** - Invalid or missing API key | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------- | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INVALID_REQUEST_BODY` | 400 | Invalid request body | | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Pagination Guide When using pagination: 1. **Enable pagination** by setting `isPagination` to `true` (GET) or `true` (POST) 2. **Start with page 1** using `pageNumber=1` (GET) or `pageNumber: 1` (POST) 3. **Each page returns up to 10 dashboards** 4. **Continue to next page** if you receive exactly 10 results 5. **Stop pagination** when you receive fewer than 10 results ### GET Method Pagination Example: ``` GET /api/v2/data-app/dashboards?isPagination=true&pageNumber=1 ``` ### POST Method Pagination Example: ```json theme={"dark"} { "isPagination": true, "pageNumber": 1 } ``` ## Filtering Options ### Dashboard Name Filtering **GET Method:** Use comma-separated values in query parameter ``` ?dashboardNames=Dashboard%201,Dashboard%202 ``` **POST Method:** Use array in request body ```json theme={"dark"} { "filters": { "dashboardNames": ["Dashboard 1", "Dashboard 2"] } } ``` This is useful when you know the exact dashboard names you want to work with. ## Migration Guide: POST to GET If you're currently using the POST method, here's how to migrate to GET: ### Before (POST): ```javascript theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/dashboards', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ isPagination: true, pageNumber: 1, filters: { dashboardNames: ['Sales Dashboard'] } }) }); ``` ### After (GET): ```javascript theme={"dark"} const params = new URLSearchParams({ isPagination: 'true', pageNumber: '1', dashboardNames: 'Sales Dashboard' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/dashboards?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_...' } }); ``` ### Key Differences: 1. **Method**: POST → GET 2. **Parameters**: Request body → Query parameters 3. **Boolean values**: `true` → `"true"` (string in query params) 4. **Number values**: `1` → `"1"` (string in query params) 5. **Dashboard names**: Array `["name1", "name2"]` → Comma-separated string `"name1,name2"` 6. **Content-Type header**: Not needed for GET ## Quick Start Guide For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). Get all dashboards available in your data app: ```bash theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' ``` If you're looking for specific dashboards, use query parameters: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/dashboards?dashboardNames=Sales%20Dashboard,Marketing%20Analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Process the dashboard data to create embed configurations: ```javascript theme={"dark"} const dashboards = await fetchDataAppDashboards(); dashboards.data.forEach(dashboard => { console.log(`Dashboard: ${dashboard.name}`); console.log(`External ID: ${dashboard.externalDashboardId}`); // Use the externalDashboardId to create embed configurations if (!dashboard.embedId) { console.log('This dashboard can be made embeddable'); } }); ``` ## Next Steps Use dashboard IDs to create embed configurations Get metrics available for specific embedded dashboards Query data from your dashboard metrics Generate secure tokens for embedded access # Fetch metric data by data app Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/fetch-metric-data-by-dataapp POST https://api.usedatabrain.com/api/v2/data-app/query Execute queries on metrics within your embedded dashboards and retrieve the resulting data. Query specific metrics from your embedded dashboards to retrieve data programmatically. This endpoint allows you to fetch metric data with optional filtering and is essential for building custom analytics interfaces or exporting data from your embedded dashboards. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/query`. The old endpoint `/api/v2/dataApp/query` will be deprecated soon. Please update your integrations to use the new endpoint format. This endpoint requires an embed ID, metric ID, and client ID. The metric must be associated with the specified embed configuration for the query to succeed. ## Endpoint Formats ``` POST https://api.usedatabrain.com/api/v2/data-app/query ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/query ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/query \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The unique identifier of the embed configuration containing the metric. * Use the List All Embeds API to get embed IDs * Check the response from embed creation * Available in the DataBrain dashboard when viewing embed configurations The unique identifier of the metric to query. * Available in the metric URL: `/metric/{metricId}` * Retrieved via the [Fetch Metrics by Embed](/developer-docs/helpers/api-reference/fetch-metrics-by-embed-and-client) API * Found in the DataBrain dashboard when viewing a metric Unique identifier for the end user making the query. Used for row-level security and access control. * Should match the clientId used in guest token generation * Used for applying row-level security filters * Consistent across user sessions * Enables multi-tenant data isolation Dashboard-level filters to apply to the metric query. These filters affect the entire dashboard context. ```json theme={"dark"} { "date_range": { "start": "2024-01-01", "end": "2024-01-31" }, "region": "north-america", "product_category": "electronics" } ``` Metric-specific filters to apply to the query. Used for row-level security and additional filtering. ```json theme={"dark"} { "customer_segment": "enterprise", "product_category": "software", "status": "active" } ``` Optional string. Use when the dashboard’s workspace is configured for **multiple datasources** (`MULTI_DATASOURCE`): pass the datasource **name** (as in Data Studio / your integration credentials) so the query runs against that datasource. If the name does not resolve, the API returns `DATASOURCE_NAME_ERROR` (400). * Not used for multi-datamart workspaces; use `dataMartName` instead when applicable * For workspaces that are not multi-datasource, omit this field unless your integration already relies on it Optional string. Use the exact JSON property name **`dataMartName`** (camelCase with a capital **M** in `Mart`). When the dashboard’s workspace is configured for **multiple datamarts** (`MULTI_DATAMART`), pass the datamart **name** so the query resolves that datamart’s linked datasource. Names follow the same rules as in the [List Datamarts](/developer-docs/helpers/api-reference/list-datamarts) API. If the name does not resolve, the API returns `DATAMART_NAME_ERROR` (400). * Not used for multi-datasource workspaces; use `datasourceName` instead when applicable * Distinct from workspace create/update body field `datamartName` (different casing for this endpoint) ## Response Array of objects containing the query results. Each object represents a row of data with column names as keys. ```json Example theme={"dark"} [ { "date": "2024-01-01", "revenue": 15000, "region": "north-america" }, { "date": "2024-01-02", "revenue": 18000, "region": "north-america" } ] ``` Query execution time in milliseconds. Comparison value for metrics with comparison enabled. Total number of records in the result set. Metadata about the query results. Array of column information. Column name. Data type of the column (e.g., "string", "number", "date"). List of columns used in GROUP BY operations. The metric ID that was queried (echo of request parameter). Error object if the request failed, otherwise `null` for successful requests. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/query \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_123", "metricId": "metric_456", "clientId": "user_789", "dashboardFilter": { "date_range": { "start": "2024-01-01", "end": "2024-01-31" } }, "metricFilter": { "region": "north-america" } }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/query', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId: 'embed_123', metricId: 'metric_456', clientId: 'user_789', dashboardFilter: { date_range: { start: '2024-01-01', end: '2024-01-31' } }, metricFilter: { region: 'north-america' } }) }); const data = await response.json(); console.log('Query results:', data.data.length, 'rows'); console.log('Time taken:', data.timeTaken, 'ms'); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests import json url = "https://api.usedatabrain.com/api/v2/data-app/query" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } payload = { "embedId": "embed_123", "metricId": "metric_456", "clientId": "user_789", "dashboardFilter": { "date_range": { "start": "2024-01-01", "end": "2024-01-31" } }, "metricFilter": { "region": "north-america" } } response = requests.post(url, headers=headers, data=json.dumps(payload)) data = response.json() print(f"Query results: {len(data['data'])} rows") print(f"Time taken: {data['timeTaken']} ms") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/query') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { embedId: 'embed_123', metricId: 'metric_456', clientId: 'user_789', dashboardFilter: { date_range: { start: '2024-01-01', end: '2024-01-31' } }, metricFilter: { region: 'north-america' } }.to_json response = http.request(request) data = JSON.parse(response.body) puts "Query results: #{data['data'].length} rows" puts "Time taken: #{data['timeTaken']} ms" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.HashMap; public class DataBrainQueryAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); ObjectMapper mapper = new ObjectMapper(); Map dashboardFilter = new HashMap<>(); Map dateRange = new HashMap<>(); dateRange.put("start", "2024-01-01"); dateRange.put("end", "2024-01-31"); dashboardFilter.put("date_range", dateRange); Map metricFilter = new HashMap<>(); metricFilter.put("region", "north-america"); Map requestBody = new HashMap<>(); requestBody.put("embedId", "embed_123"); requestBody.put("metricId", "metric_456"); requestBody.put("clientId", "user_789"); requestBody.put("dashboardFilter", dashboardFilter); requestBody.put("metricFilter", metricFilter); String jsonBody = mapper.writeValueAsString(requestBody); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/query")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type QueryRequest struct { EmbedId string `json:"embedId"` MetricId string `json:"metricId"` ClientId string `json:"clientId"` DashboardFilter map[string]interface{} `json:"dashboardFilter,omitempty"` MetricFilter map[string]interface{} `json:"metricFilter,omitempty"` } type QueryResponse struct { Data []map[string]interface{} `json:"data"` TimeTaken int `json:"timeTaken"` TotalRecords int `json:"totalRecords"` MetaData map[string]interface{} `json:"metaData"` } func main() { reqBody := QueryRequest{ EmbedId: "embed_123", MetricId: "metric_456", ClientId: "user_789", DashboardFilter: map[string]interface{}{ "date_range": map[string]string{ "start": "2024-01-01", "end": "2024-01-31", }, }, MetricFilter: map[string]interface{}{ "region": "north-america", }, } jsonData, _ := json.Marshal(reqBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/query", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var queryResp QueryResponse json.NewDecoder(resp.Body).Decode(&queryResp) fmt.Printf("Query results: %d rows\n", len(queryResp.Data)) fmt.Printf("Time taken: %d ms\n", queryResp.TimeTaken) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'embed_123', 'metricId' => 'metric_456', 'clientId' => 'user_789', 'dashboardFilter' => [ 'date_range' => [ 'start' => '2024-01-01', 'end' => '2024-01-31' ] ], 'metricFilter' => [ 'region' => 'north-america' ] ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Query results: " . count($response['data']) . " rows\n"; echo "Time taken: " . $response['timeTaken'] . " ms\n"; ?> ``` ```json Success Response theme={"dark"} { "data": [ { "date": "2024-01-01", "revenue": 15000, "region": "north-america", "customer_count": 45 }, { "date": "2024-01-02", "revenue": 18500, "region": "north-america", "customer_count": 52 }, { "date": "2024-01-03", "revenue": 16500, "region": "north-america", "customer_count": 138 } ], "timeTaken": 245, "comparisonValue": 12500, "totalRecords": 31, "metaData": { "columns": [ { "name": "date", "dataType": "date" }, { "name": "revenue", "dataType": "number" }, { "name": "region", "dataType": "string" }, { "name": "customer_count", "dataType": "number" } ], "groupbyColumnList": ["date", "region"] }, "metricid": "metric_456", "error": null } ``` ```json Empty Results Response theme={"dark"} { "data": [], "timeTaken": 45, "totalRecords": 0, "metaData": { "columns": [], "groupbyColumnList": [] }, "metricid": "metric_456", "error": null } ``` ```json Error Response (401) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Invalid or missing Data App API Key" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_EMBED_ID", "message": "Embed ID not found or access denied", "status": 400 } } ``` ```json Error Response (404) theme={"dark"} { "error": { "code": "EMBED_PARAM_ERROR", "message": "Embed ID not found or mismatched with API Key" } } ``` ## Error Codes **Invalid embed ID** - The specified embed ID doesn't exist or you don't have access **Invalid metric ID** - The specified metric ID doesn't exist or isn't associated with the embed **Missing or invalid data app** - Check your API key and data app configuration **Embed ID error** - The embed ID was not found or doesn't match the API key being used **Metric not found** - The specified metric ID doesn't exist or isn't associated with the embed configuration **Invalid datasource name** - The specified datasource name could not be resolved for a multi-datasource workspace **Invalid datamart name** - The specified `dataMartName` could not be resolved for a multi-datamart workspace ## HTTP Status Code Summary | Status Code | Description | | ----------- | ----------------------------------------------------------------------- | | `200` | **OK** - Query executed successfully | | `400` | **Bad Request** - Invalid request parameters or missing required fields | | `401` | **Unauthorized** - Invalid or expired API token | | `404` | **Not Found** - Embed ID or metric ID not found | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Unexpected server error | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------ | | `INVALID_EMBED_ID` | 400 | Embed ID not found | | `INVALID_METRIC_ID` | 400 | Invalid metric ID | | `INVALID_DATA_APP_API_KEY` | 401 | Missing or invalid data app | | `EMBED_PARAM_ERROR` | 404 | Embed ID error | | `METRIC_NOT_FOUND` | 404 | Metric not found | | `DATASOURCE_NAME_ERROR` | 400 | Invalid datasource name (multi-datasource) | | `DATAMART_NAME_ERROR` | 400 | Invalid datamart name (multi-datamart) | | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | | `INTERNAL_SERVER_ERROR` | 500 | Unexpected failure | ## Filtering Guide ### Dashboard Filters Dashboard filters apply to the entire dashboard context and affect all metrics. Common use cases include: * **Date range filtering**: Limit data to specific time periods * **Category filtering**: Filter by region, department, product line, etc. * **Global parameters**: Set values that affect multiple metrics ```json Example theme={"dark"} { "dashboardFilter": { "date_range": { "start": "2024-01-01", "end": "2024-03-31" }, "region": "north-america", "product_category": "electronics" } } ``` ### Metric Filters Metric filters apply specifically to the metric being queried and can be used for: * **Row-level security (RLS)**: Restrict data based on client permissions * **Additional filtering**: Apply metric-specific conditions * **Client isolation**: Ensure multi-tenant data separation ```json Example theme={"dark"} { "metricFilter": { "department": "sales", "status": "active", "client_group": "enterprise" } } ``` ## Use Cases ### Export Dashboard Data ```javascript theme={"dark"} async function exportDashboardData(embedId, clientId) { // Get all metrics const metricsResponse = await fetch( `https://api.usedatabrain.com/api/v2/data-app/metrics?embedId=${embedId}&clientId=${clientId}`, { headers: { 'Authorization': 'Bearer dbn_live_...' } } ); const { data: metrics } = await metricsResponse.json(); // Query each metric const allData = {}; for (const metric of metrics) { const queryResponse = await fetch( 'https://api.usedatabrain.com/api/v2/data-app/query', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId, metricId: metric.metricId, clientId }) } ); const queryResult = await queryResponse.json(); allData[metric.name] = queryResult.data; } return allData; } ``` ### Real-time Data Refresh ```javascript theme={"dark"} async function refreshMetricData(embedId, metricId, clientId, filters) { const response = await fetch( 'https://api.usedatabrain.com/api/v2/data-app/query', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId, metricId, clientId, dashboardFilter: filters }) } ); return await response.json(); } // Refresh every 5 minutes setInterval(async () => { const data = await refreshMetricData( 'embed_123', 'metric_456', 'user_789', { date_range: { start: 'today', end: 'today' } } ); updateDashboard(data); }, 5 * 60 * 1000); ``` ### Multi-Tenant Data Access ```javascript theme={"dark"} async function getClientMetricData(embedId, metricId, clientId) { // Apply client-specific filters automatically const response = await fetch( 'https://api.usedatabrain.com/api/v2/data-app/query', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId, metricId, clientId, metricFilter: { // RLS ensures clients only see their data client_id: clientId } }) } ); return await response.json(); } ``` ## Best Practices 1. **Cache responses** - Cache query results when appropriate to reduce API calls and improve performance 2. **Use filters efficiently** - Apply filters at the query level rather than filtering data client-side 3. **Handle pagination** - For large datasets, implement pagination or limit results 4. **Error handling** - Implement robust error handling and retry logic 5. **Rate limiting** - Respect rate limits and implement exponential backoff 6. **Security** - Never expose API keys in client-side code; proxy requests through your backend ## Performance Tips * **Minimize filter complexity** - Complex filters can slow down queries * **Request only needed columns** - If possible, select only required columns * **Use date ranges** - Limit queries to specific time periods * **Cache when possible** - Cache frequently accessed data * **Batch requests** - When querying multiple metrics, consider batching requests ## Quick Start Guide First, get your embed ID and metric ID from your DataBrain dashboard or via the List APIs: ```bash theme={"dark"} # List your embeds to find the embedId curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Use the [Fetch Metrics by Embed](/developer-docs/helpers/api-reference/fetch-metrics-by-embed-and-client) endpoint to get a list of available metrics: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/metrics?embedId=embed_123&clientId=user_789' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Query a metric with minimal parameters: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/query \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_123", "metricId": "metric_456", "clientId": "user_789" }' ``` Include filters to narrow down your results: ```bash theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/query \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_123", "metricId": "metric_456", "clientId": "user_789", "dashboardFilter": { "date_range": { "start": "2024-01-01", "end": "2024-01-31" } } }' ``` Use the returned data in your application: ```javascript theme={"dark"} const queryData = await queryMetric({ embedId: 'embed_123', metricId: 'metric_456', clientId: 'user_789' }); console.log(`Found ${queryData.totalRecords} records`); console.log(`Query took ${queryData.timeTaken}ms`); queryData.data.forEach(row => { // Process each data row console.log(row); }); ``` ## Next Steps Get a list of available metrics before querying Retrieve available dashboards in your data app Set up embed configurations for your data app Generate secure tokens for embedded access # Fetch Metrics by Embed and Client Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/fetch-metrics-by-embed-and-client GET https://api.usedatabrain.com/api/v2/data-app/metrics?embedId={id}&clientId={client_xyz789}&isPagination=true&pageNumber=1 Retrieve metrics available for a specific embed configuration and client, with support for pagination and client-specific filtering. Get a list of metrics that are accessible through a specific embed configuration for a particular client. This endpoint is essential for understanding what metrics are available for querying within an embedded dashboard context. This endpoint returns metrics filtered by client access. Client-created metrics are only visible to the specific client that created them, while shared metrics are visible to all clients. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/metrics \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The embed configuration ID to fetch metrics for. This identifies which embedded dashboard's metrics you want to retrieve. * Created when you configure an embed via the [Create Embed API](/developer-docs/helpers/api-reference/create-embed) * Retrieved via the [List Embeds API](/developer-docs/helpers/api-reference/list-embed) * Available in your DataBrain dashboard embed settings The client identifier for filtering metrics. Determines which metrics the client has access to based on their permissions and ownership. Enable pagination to limit the number of results returned. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number for pagination (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). When set to `"true"`, returns only the list of metrics — excluding elements and summaries. Pass `"false"` or omit this parameter to return all items, including non-metric components. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Filter metrics by the user identifier who created them. When provided, only returns metrics created by the specified user. * When `userIdentifier` is provided: Returns only metrics where `createdByIdentifier` matches * When omitted: Returns all metrics the client has access to * System-created metrics (no creator) are excluded when filtering by user * Useful for showing "My Metrics" views in your application ## Response Array of metric objects available for the specified embed and client. Display name of the metric. Unique identifier for the metric that can be used in query operations. Indicates whether the metric is published and visible to end users. * `true`: Metric is published and visible * `false`: Metric is unpublished (hidden but not deleted) * System-created metrics (without a creator) are always `true` The identifier of the user who created this metric, or `null` for system-created metrics. * Non-null value: Indicates a user-created metric with the creator's identifier * `null`: Indicates a system-created or admin-created metric * Useful for implementing "My Metrics" filtering and ownership displays Error object returned only when the request fails. Not present in successful responses. Machine-readable error code for programmatic handling. Human-readable error message explaining what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/metrics?embedId=embed_abc123&clientId=client_xyz789&isPagination=true&pageNumber=1&isMetric=true' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js theme={"dark"} const params = new URLSearchParams({ embedId: 'embed_abc123', clientId: 'client_xyz789', isPagination: 'true', pageNumber: '1', isMetric: 'true' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/metrics?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Available metrics:', data.data); ``` ```python Python theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/metrics" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "embedId": "embed_abc123", "clientId": "client_xyz789", "isPagination": "true", "pageNumber": "1", "isMetric": "true" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Available metrics: {data['data']}") ``` ```ruby Ruby theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/metrics') params = { embedId: 'embed_abc123', clientId: 'client_xyz789', isPagination: 'true', pageNumber: '1', isMetric: 'true' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Available metrics: #{data['data']}" ``` ```java Java theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainMetricsAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String url = "https://api.usedatabrain.com/api/v2/data-app/metrics" + "?embedId=embed_abc123&clientId=client_xyz789&isPagination=true&pageNumber=1&isMetric=true"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type Metric struct { Name string `json:"name"` MetricID string `json:"metricId"` IsPublished bool `json:"isPublished"` CreatedByUser *string `json:"createdByUser"` } type MetricResponse struct { Data []Metric `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/metrics" params := url.Values{} params.Add("embedId", "embed_abc123") params.Add("clientId", "client_xyz789") params.Add("isPagination", "true") params.Add("pageNumber", "1") params.Add("isMetric", "true") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var metricResp MetricResponse json.NewDecoder(resp.Body).Decode(&metricResp) fmt.Printf("Available metrics: %+v\n", metricResp.Data) } ``` ```php PHP theme={"dark"} 'embed_abc123', 'clientId' => 'client_xyz789', 'isPagination' => 'true', 'pageNumber' => '1', 'isMetric' => 'true' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/metrics?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Available metrics: " . print_r($response['data'], true); ?> ``` ```json Success Response theme={"dark"} { "data": [ { "name": "Total Revenue", "metricId": "metric_revenue_123", "isPublished": true, "createdByUser": null }, { "name": "Active Users", "metricId": "metric_users_456", "isPublished": true, "createdByUser": "user_abc123" }, { "name": "Conversion Rate", "metricId": "metric_conversion_789", "isPublished": false, "createdByUser": "user_abc123" } ] } ``` ```json Empty Results Response theme={"dark"} { "data": [] } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "EMBED_PARAM_ERROR", "message": "invalid embed id, embed id not found for given data app" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"embedId\" is required" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------------------------------------------------- | | `200` | **OK** - Metrics retrieved successfully | | `400` | **Bad Request** - Invalid request parameters, missing required fields, invalid API key, or embed ID not found | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------- | | `INVALID_DATA_APP_API_KEY` | 400 | Invalid or expired API key | | `EMBED_PARAM_ERROR` | 400 | Embed ID not found for data app | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid required parameters | ## Client Access Control ### Metric Visibility Rules 1. **Shared Metrics**: Available to all clients within the embed 2. **Client-Created Metrics**: Only visible to the client that created them 3. **Access Settings**: Controlled by the embed configuration's access settings ### Understanding Client-Specific Results The API automatically filters metrics based on the client's access permissions: ```javascript theme={"dark"} // Client A will see their own metrics + shared metrics const clientAMetrics = await fetchMetrics('embed_123', 'client_A'); // Client B will see their own metrics + shared metrics (different from Client A) const clientBMetrics = await fetchMetrics('embed_123', 'client_B'); ``` # Fetch Metrics by Workspace Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/fetch-metrics-by-workspace POST https://api.usedatabrain.com/api/v2/workspace/metrics Retrieve metrics from a workspace with optional pagination support. Retrieve metrics available in a workspace. Use this endpoint to discover metrics for provisioning and embedding in your application. This endpoint operates at the workspace level using a service token. Use the workspace name to scope which metrics are returned. Supports pagination for workspaces with many metrics. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the workspace to fetch metrics from. Must match an existing workspace in your organization. * Use the [List Workspaces](/developer-docs/helpers/api-reference/list-workspaces) endpoint to see all available workspaces * Names are case-sensitive * Must be an exact match Enable pagination to retrieve metrics in batches of 10. * `true`: Enable pagination with page-based retrieval (10 items per page) * `false` (default): Return all metrics in a single response - Use pagination when you have more than 20 metrics in a workspace - Improves response times for large datasets - Each page returns up to 10 metrics The page number to retrieve when pagination is enabled. Pages are 1-indexed. **Note:** This parameter is only used when `isPagination` is set to `true`. ## Response Array of metric objects. Returns empty array if no metrics exist or page number exceeds available pages. Display name of the metric. Unique identifier for the metric. Error object if the request failed, otherwise `null` for successful requests. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - All Metrics theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace/metrics \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "my-workspace" }' ``` ```bash cURL - With Pagination theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/workspace/metrics \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "my-workspace", "isPagination": true, "pageNumber": 1 }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace/metrics', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ workspaceName: 'my-workspace', isPagination: true, pageNumber: 1 }) }); const result = await response.json(); console.log('Metrics:', result.data); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/workspace/metrics', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'workspaceName': 'my-workspace', 'isPagination': True, 'pageNumber': 1 } ) result = response.json() print(f"Metrics: {result['data']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/workspace/metrics') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { workspaceName: 'my-workspace', isPagination: true, pageNumber: 1 }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Metrics: #{result['data']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class FetchMetrics { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "workspaceName": "my-workspace", "isPagination": true, "pageNumber": 1 } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/workspace/metrics")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) type MetricsRequest struct { WorkspaceName string `json:"workspaceName"` IsPagination bool `json:"isPagination,omitempty"` PageNumber int `json:"pageNumber,omitempty"` } func main() { reqData := MetricsRequest{ WorkspaceName: "my-workspace", IsPagination: true, PageNumber: 1, } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/workspace/metrics", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'my-workspace', 'isPagination' => true, 'pageNumber' => 1 ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'POST', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); print_r($result['data']); ?> ``` ```json 200 - Success theme={"dark"} { "data": [ { "name": "Monthly Revenue", "metricId": "metric_abc123" }, { "name": "Active Users", "metricId": "metric_def456" } ], "error": null } ``` ```json 200 - Empty Results theme={"dark"} { "data": [], "error": null } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"workspaceName\" is required" } } ``` ```json 400 - Workspace Not Found theme={"dark"} { "error": { "code": "WORKSPACE_ID_ERROR", "message": "The workspace name provided does not exist" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "API Key is not provided or Invalid!" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Metrics retrieved successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------ | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid request body parameters | | `WORKSPACE_ID_ERROR` | 400 | Workspace name does not exist | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid or expired API key | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Next Steps Retrieve dashboards from a workspace List all workspaces in your organization Create a new workspace for your analytics environment Generate secure tokens for embedded access # Get AWSS3 sync Progress status Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/get-awss3-sync-progress-status POST https://api.usedatabrain.com/api/v2/datasource/getDatasourceProgress ## Endpoint: ```bash theme={"dark"} POST /datasource/getDatasourceProgress ``` ## Headers Bearer [API TOKEN](https://docs.usedatabrain.com/developer-docs/helpers/api-token) ## Request Body Input object containing the datasource configuration. The unique identifier of the datasource to check sync progress for. ## Request Example ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource/getDatasourceProgress \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "input": { "datasourceId": "your-datasource-id" } }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/datasource/getDatasourceProgress', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ input: { datasourceId: 'your-datasource-id' } }) }); const data = await response.json(); console.log('Progress:', data.status.progress); console.log('Error:', data.status.error); ``` ```python Python theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/datasource/getDatasourceProgress', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'input': { 'datasourceId': 'your-datasource-id' } } ) data = response.json() print(f"Progress: {data['status']['progress']}") print(f"Error: {data['status']['error']}") ``` ## Response Body ```json theme={"dark"} { "status": { "progress": "16/16", "error": "" } } ``` ### Response Body: Below is a response when no sync is completed for AWSS3: ```json theme={"dark"} { "status": { "progress": "0/...", "error": "" } } ``` ### Response Error: Below is a response error when while syncing AWSS3 throws an error: ```json theme={"dark"} { "status": { "progress": "0/...", "error": "Error: Bind error data type" } } ``` ## Error Codes * **INVALID\_REQUEST\_BODY**: The request body is invalid. * **DATASOURCE\_ID\_ERROR**: The datasource ID provided does not exist or is invalid. # Get Semantic Layer Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/get-semantic-layer GET https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer Retrieve the semantic layer configuration for a datamart, including table descriptions, column metadata, and completion score. Retrieve the full semantic layer for a given datamart. The response includes table and column metadata (descriptions, synonyms, column types), feedback text, a completion score, and the last-updated timestamp. This endpoint returns data for datamarts that exist in your organization — even if no semantic layer has been configured yet. In that case, tables are returned with `null`/empty semantic fields. ## Authentication This endpoint requires a **service token** in the Authorization header. Data app API tokens are not permitted and will be rejected with a `403` error. To access your service token: 1. Go to your Databrain dashboard and open **Settings**. 2. Navigate to **Settings**. 3. Find the **Service Tokens** section. 4. Click the **"Generate Token"** button to generate a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The name of the datamart whose semantic layer you want to retrieve. Must match an existing datamart in your organization. * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to get all datamart names * Names are case-sensitive and must match exactly ## Response The semantic layer data for the requested datamart. Name of the datamart. Array of table objects with semantic metadata. Table name from the datasource. Schema name, or `null` if not set. Human-readable description of the table. Alternative names for the table. Empty array if none set. Additional context for AI query generation. Array of column objects with semantic metadata. Column name from the datasource. The underlying SQL datatype of the column. Human-readable description of the column. Alternative names for the column. Additional context for AI query generation. Semantic column type. One of: `String`, `Long String`, `String (Custom)`, `ENUM`, `Mapper`, `Range`, `Expression`, `Identifier`, `Number`, `JSON`. Stored column-type configuration as saved via the API (object maps for ENUM-like types, `{ lowerLimit, upperLimit }` for Range, strings for Expression/JSON, or `null`). Whether this column is marked as an identifier. Whether this column is excluded from AI indexing. Global feedback text providing context to the AI about this datamart. A score from 0 to 100 indicating how thoroughly the semantic layer is configured. ISO 8601 timestamp of the last semantic layer update, or `null` if never updated. Error object if the request failed, otherwise not present for successful requests. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const datamartName = 'sales-analytics'; const response = await fetch( `https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=${encodeURIComponent(datamartName)}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); const result = await response.json(); console.log('Tables:', result.data.tables.length); console.log('Completion:', result.data.completionScore); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.get( 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', headers={ 'Authorization': 'Bearer dbn_live_abc123...' }, params={ 'datamartName': 'sales-analytics' } ) result = response.json() print(f"Tables: {len(result['data']['tables'])}") print(f"Completion: {result['data']['completionScore']}%") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer') params = { datamartName: 'sales-analytics' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) result = JSON.parse(response.body) puts "Tables: #{result['data']['tables'].length}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class GetSemanticLayer { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String datamartName = URLEncoder.encode("sales-analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=%s", datamartName ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer" params := url.Values{} params.Add("datamartName", "sales-analytics") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result map[string]interface{} json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Response: %v\n", result) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Tables: " . count($response['data']['tables']); ?> ``` ```json 200 - Success theme={"dark"} { "data": { "datamartName": "sales-analytics", "tables": [ { "name": "orders", "schemaName": "public", "description": "Customer purchase orders", "synonyms": ["purchases", "transactions"], "miscellaneousInfo": null, "columns": [ { "name": "order_id", "datatype": "integer", "description": "Unique order identifier", "synonyms": ["id", "order number"], "miscellaneousInfo": null, "columnType": "Identifier", "columnTypeConfig": null, "isIdentifier": true, "isNotIndexed": false }, { "name": "status", "datatype": "varchar", "description": "Current order status", "synonyms": ["order status", "state"], "miscellaneousInfo": null, "columnType": "ENUM", "columnTypeConfig": null, "isIdentifier": false, "isNotIndexed": false }, { "name": "amount", "datatype": "numeric", "description": "Total order amount in USD", "synonyms": ["total", "price"], "miscellaneousInfo": null, "columnType": "Number", "columnTypeConfig": null, "isIdentifier": false, "isNotIndexed": false } ] } ], "feedback": "This datamart covers e-commerce sales data. Amounts are in USD.", "completionScore": 75, "lastUpdated": "2026-03-15T10:30:00.000Z" } } ``` ```json 200 - No Semantic Data theme={"dark"} { "data": { "datamartName": "raw-datamart", "tables": [ { "name": "events", "schemaName": "public", "description": null, "synonyms": [], "miscellaneousInfo": null, "columns": [ { "name": "event_id", "datatype": "integer", "description": null, "synonyms": [], "miscellaneousInfo": null, "columnType": null, "columnTypeConfig": null, "isIdentifier": false, "isNotIndexed": false } ] } ], "feedback": null, "completionScore": 0, "lastUpdated": null } } ``` ```json 400 - Missing datamartName theme={"dark"} { "error": { "code": "INVALID_DATAMART", "message": "datamartName query parameter is required" } } ``` ```json 400 - Datamart Not Found theme={"dark"} { "error": { "code": "INVALID_DATAMART", "message": "Datamart 'nonexistent' not found" } } ``` ```json 403 - Data App Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Semantic Layer API requires a service token, not a data app API token" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------ | | `200` | **OK** — Semantic layer retrieved successfully | | `400` | **Bad Request** — Missing or invalid datamartName | | `401` | **Unauthorized** — Invalid or missing API token | | `403` | **Forbidden** — Data app token used instead of service token | | `500` | **Internal Server Error** — Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | ------------------------------------------------- | | `INVALID_DATAMART` | 400 | datamartName is missing or datamart doesn't exist | | `AUTHENTICATION_ERROR` | 403 | Data app token used instead of service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Next Steps Add semantic metadata to your datamart Modify existing semantic layer metadata Learn how to configure the semantic layer in the UI Find datamart names in your organization # Import Dashboard Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/import-dashboard POST https://api.usedatabrain.com/api/v2/data-app/import-dashboard Import a dashboard from a previously exported JSON payload into a workspace. Import a dashboard into a workspace using JSON data from the [Export Dashboard API](/developer-docs/helpers/api-reference/export-dashboard) or from a file exported via the Databrain UI. The dashboard layout, metrics, and filters are recreated in the target workspace. **Authentication Requirement:** This endpoint requires a **service token** (company-level), not a data app API key. The workspace must belong to your company. ## Authentication Use your service token in the `Authorization` header. See [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) for how to obtain a service token. ```bash Authentication theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/import-dashboard \ --header 'Authorization: Bearer YOUR_SERVICE_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"workspaceName":"Target Workspace","importDashboardData":{...}}' ``` ## Headers Bearer token for API authentication. Use your **service token** (company-level). ``` Authorization: Bearer dbn_live_... ``` Must be `application/json`. ``` Content-Type: application/json ``` ## Request Body Validated with **`importDashboardSchema`**: **`workspaceName`** (string, required) and **`importDashboardData`** (object, required) are required. **`dashboardId`**, **`dashboardName`**, and **`schemaPairs`** are optional. Each **`schemaPairs`** item must include **`replaceSchema`** and **`targetSchema`** (strings). The name of the workspace where the dashboard should be imported. Must match an existing workspace name in your company. The dashboard payload to import. Must be a non-null object. Use the `data` property from an [Export Dashboard](/developer-docs/helpers/api-reference/export-dashboard) response, or the equivalent structure from a UI-exported JSON file. Contains layout, filters, metrics configuration, and related dashboard structure. * From **Export Dashboard API**: use the `data` property of the exported JSON. * From **UI export file**: use the `data` property from the downloaded JSON file. Optional stable identifier for the imported dashboard in the target workspace. * If provided, this value is used as the external dashboard ID. * If omitted, a new unique ID is generated automatically. * If a dashboard with the same ID already exists in the target workspace, the import returns an error message and no new dashboard is created. Optional display name to assign to the imported dashboard in the target workspace. If omitted, the name from the exported payload is used. Optional. Maps schema names in the exported SQL/dashboard payload to schema names in the target workspace (for example when moving from staging to production). Each array element is an object with: * **`replaceSchema`** — string (required in each item) * **`targetSchema`** — string (required in each item) ```json theme={"dark"} "schemaPairs": [ { "replaceSchema": "databrain_dev1", "targetSchema": "databrain_dev2" } ] ``` ## Response Result of the import operation. On success, `data.response` contains: * `message` – human-readable summary of the import (including the number of imported metrics) * `dashboardId` – external dashboard ID in the target workspace * `dashboardName` – name of the imported dashboard in the target workspace * `workspaceName` – name of the workspace where the dashboard was imported On error, the API returns a JSON object with `error.code` and `error.message` and HTTP status 400 or 500. ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url 'https://api.usedatabrain.com/api/v2/data-app/import-dashboard' \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "Target Workspace", "importDashboardData": { "layout": [], "filters": [], "gridMargin": {} }, "dashboardId": "sales-dashboard-1-copy", "dashboardName": "Sales Dashboard (Copy)", "schemaPairs": [ { "replaceSchema": "source_schema", "targetSchema": "public" } ] }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} // Assume exportedJson is the object from Export Dashboard API or from reading the exported file const exportedJson = { _meta: {...}, data: {...} }; const importDashboardData = exportedJson.data || exportedJson; const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/import-dashboard', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_...', 'Content-Type': 'application/json' }, body: JSON.stringify({ workspaceName: 'Target Workspace', importDashboardData, dashboardId: 'sales-dashboard-1-copy', dashboardName: 'Sales Dashboard (Copy)', schemaPairs: [ { replaceSchema: 'source_schema', targetSchema: 'public' } ] }) }); const result = await response.json(); if (result.error) { throw new Error(result.error.message); } console.log('Imported:', result.data); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/import-dashboard" headers = { "Authorization": "Bearer dbn_live_...", "Content-Type": "application/json" } # Use the "data" part of an exported dashboard JSON payload = { "workspaceName": "Target Workspace", "importDashboardData": { "layout": [], "filters": [], "gridMargin": {} }, "dashboardId": "sales-dashboard-1-copy", "dashboardName": "Sales Dashboard (Copy)", "schemaPairs": [ {"replaceSchema": "source_schema", "targetSchema": "public"} ] } response = requests.post(url, headers=headers, json=payload) data = response.json() if "error" in data: raise Exception(data["error"].get("message", "Import failed")) print("Imported:", data.get("data")) ``` ```json Success Response theme={"dark"} { "data": { "response": { "message": "Imported Dashboard with 10 metrics", "dashboardId": "sales-dashboard-1-copy", "dashboardName": "Sales Dashboard (Copy)", "workspaceName": "Target Workspace" } } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"workspaceName\" is required" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "WORKSPACE_ID_ERROR", "message": "invalid workspace name, workspace name not found" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | -------------------------------------------------------------------------------------- | | `200` | **OK** – Dashboard imported successfully | | `400` | **Bad Request** – Invalid or missing parameters, invalid token, or workspace not found | | `500` | **Internal Server Error** – Server error during import | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | --------------------------------------------------------------------------------------- | ----------- | | `INVALID_REQUEST_BODY` | Joi validation message (e.g. `"workspaceName" is required`, invalid `schemaPairs` item) | 400 | | `AUTHENTICATION_ERROR` | Invalid Service Token (e.g. missing/invalid company context on token) | 400 | | `WORKSPACE_ID_ERROR` | invalid workspace name, workspace name not found | 400 | | `INTERNAL_SERVER_ERROR` | Server error message | 500 | ## Related * [Export Dashboard](/developer-docs/helpers/api-reference/export-dashboard) – Export a dashboard to get the payload for import * [Import/Export Dashboard (UI)](/guides/dashboards/import-export-dashboard) – UI guide for import/export # List API Tokens for Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-api-tokens GET https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName={name} Retrieve a list of all API tokens associated with a specific Data App. Get a list of all API tokens for a specific Data App. This is useful for managing and auditing API tokens associated with your Data Apps. **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage API tokens across your organization. ## Endpoint Formats ``` GET https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName={name} ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` GET https://api.usedatabrain.com/api/v2/dataApp/api-tokens?dataAppName={name} ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` ## Query Parameters The name of the Data App to list API tokens for. This must exactly match an existing Data App name. * Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to get all Data App names * Check your Databrain dashboard for Data App configurations * The name is case-sensitive Whether to paginate results. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number to retrieve (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). ## Response Array of API token objects with their metadata. The API key value (UUID). Use this key for authentication when making API requests. The descriptive name/label assigned to the API token when it was created. The description of the API token, typically indicating the Data App it belongs to. ISO 8601 formatted timestamp indicating when the API token was created. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Get All Tokens theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName=Customer%20Portal%20Analytics' \ --header 'Authorization: Bearer service_token_xyz...' ``` ```bash cURL - With Pagination theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName=Customer%20Portal%20Analytics&isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer service_token_xyz...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const dataAppName = 'Customer Portal Analytics'; const params = new URLSearchParams({ dataAppName: dataAppName, isPagination: 'true', pageNumber: '1' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/api-tokens?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer service_token_xyz...' } }); const data = await response.json(); console.log('Found API Tokens:', data.data.length); data.data.forEach(token => { console.log(`- ${token.name} (created: ${token.createdAt})`); }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/api-tokens" headers = { "Authorization": "Bearer service_token_xyz..." } params = { "dataAppName": "Customer Portal Analytics", "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Found API Tokens: {len(data['data'])}") for token in data['data']: print(f"- {token['name']} (created: {token['createdAt']})") ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; public class ListApiTokens { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String dataAppName = URLEncoder.encode("Customer Portal Analytics", StandardCharsets.UTF_8); String url = String.format( "https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName=%s&isPagination=true&pageNumber=1", dataAppName ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer service_token_xyz...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type ApiToken struct { Id string `json:"id"` Name string `json:"name"` Description string `json:"description"` CreatedAt string `json:"createdAt"` } type ListApiTokensResponse struct { Data []ApiToken `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/api-tokens" params := url.Values{} params.Add("dataAppName", "Customer Portal Analytics") params.Add("isPagination", "true") params.Add("pageNumber", "1") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer service_token_xyz...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result ListApiTokensResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Found API Tokens: %d\n", len(result.Data)) for _, token := range result.Data { fmt.Printf("- %s (created: %s)\n", token.Name, token.CreatedAt) } } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Customer Portal Analytics', 'isPagination' => 'true', 'pageNumber' => '1' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/api-tokens?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer service_token_xyz...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Found API Tokens: " . count($response['data']) . "\n"; foreach ($response['data'] as $token) { echo "- " . $token['name'] . " (created: " . $token['createdAt'] . ")\n"; } ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/api-tokens') params = { dataAppName: 'Customer Portal Analytics', isPagination: 'true', pageNumber: '1' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' response = http.request(request) result = JSON.parse(response.body) puts "Found API Tokens: #{result['data'].length}" result['data'].each do |token| puts "- #{token['name']} (created: #{token['createdAt']})" end ``` ```json 200 - Success theme={"dark"} { "data": [ { "key": "550e8400-e29b-41d4-a716-446655440000", "name": "Production API Key", "description": "API key for data app Customer Portal Analytics", "createdAt": "2024-01-15T10:30:00Z" }, { "key": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "name": "Development Token", "description": "API key for data app Customer Portal Analytics", "createdAt": "2024-01-10T14:15:00Z" }, { "key": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d", "name": "Staging Environment", "description": "API key for data app Customer Portal Analytics", "createdAt": "2024-01-08T09:00:00Z" } ] } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"dataAppName\" is required" } } ``` ```json 400 - Data App Not Found theme={"dark"} { "error": { "code": "DATA_APP_NOT_FOUND", "message": "Data app not found" } } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - API tokens retrieved successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | ---------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid dataAppName | | `DATA_APP_NOT_FOUND` | 400 | Data App with given name not found | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide In **Settings** page, navigate to the **Service Tokens** section. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to find the Data App name: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` Get all API tokens for the Data App: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/api-tokens?dataAppName=My%20Data%20App' \ --header 'Authorization: Bearer service_token_xyz...' ``` Use the token information to manage your API keys: ```javascript theme={"dark"} const tokens = await listApiTokens({ dataAppName: 'My Data App' }); tokens.data.forEach(token => { console.log(`Token: ${token.name}`); console.log(` Key: ${token.key}`); console.log(` Created: ${token.createdAt}`); // Check if token is old and might need rotation const createdDate = new Date(token.createdAt); const daysSinceCreation = (Date.now() - createdDate) / (1000 * 60 * 60 * 24); if (daysSinceCreation > 90) { console.log(` ⚠️ Consider rotating this token (${Math.floor(daysSinceCreation)} days old)`); } }); ``` ## Next Steps Generate new API tokens for your Data Apps Rotate API keys for enhanced security View all Data Apps in your organization Use your API tokens to create embed configurations # List Data Apps Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-data-apps GET https://api.usedatabrain.com/api/v2/data-app Retrieve a list of all Data Apps in your organization with their embed configurations. Get a comprehensive list of all Data Apps in your organization, including their embed configurations, creation timestamps, and embed counts. This endpoint returns all Data Apps of type "embedded" in your organization. Each Data App includes summary information about its associated embeds. **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage Data Apps across your organization. ## Endpoint Formats ``` GET https://api.usedatabrain.com/api/v2/data-app ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` GET https://api.usedatabrain.com/api/v2/dataApp ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` ## Query Parameters Whether to paginate results. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number to retrieve (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). ## Response Array of Data App objects with their configuration details. The name of the Data App. The type of the Data App. Currently always `"embedded"`. ISO 8601 formatted timestamp indicating when the Data App was created. ISO 8601 formatted timestamp indicating when the Data App was last updated. The total number of embed configurations associated with this Data App. Array of embed configurations associated with this Data App. The name of the embed configuration. The unique identifier for the embed configuration. ISO 8601 formatted timestamp indicating when the embed was created. ISO 8601 formatted timestamp indicating when the embed was last updated. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Get All Data Apps theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` ```bash cURL - With Pagination theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer service_token_xyz...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app', { method: 'GET', headers: { 'Authorization': 'Bearer service_token_xyz...' } }); const data = await response.json(); console.log('Found Data Apps:', data.data.length); data.data.forEach(app => { console.log(`- ${app.name} (${app.embedCount} embeds)`); }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app" headers = { "Authorization": "Bearer service_token_xyz..." } params = { "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Found Data Apps: {len(data['data'])}") for app in data['data']: print(f"- {app['name']} ({app['embedCount']} embeds)") ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class ListDataApps { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String url = "https://api.usedatabrain.com/api/v2/data-app" + "?isPagination=true&pageNumber=1"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer service_token_xyz...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type Embed struct { Name string `json:"name"` EmbedId string `json:"embedId"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` } type DataApp struct { Name string `json:"name"` Type string `json:"type"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` EmbedCount int `json:"embedCount"` Embeds []Embed `json:"embeds"` } type ListDataAppsResponse struct { Data []DataApp `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app" params := url.Values{} params.Add("isPagination", "true") params.Add("pageNumber", "1") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer service_token_xyz...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result ListDataAppsResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Found Data Apps: %d\n", len(result.Data)) for _, app := range result.Data { fmt.Printf("- %s (%d embeds)\n", app.Name, app.EmbedCount) } } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'true', 'pageNumber' => '1' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer service_token_xyz...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Found Data Apps: " . count($response['data']) . "\n"; foreach ($response['data'] as $app) { echo "- " . $app['name'] . " (" . $app['embedCount'] . " embeds)\n"; } ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app') params = { isPagination: 'true', pageNumber: '1' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' response = http.request(request) result = JSON.parse(response.body) puts "Found Data Apps: #{result['data'].length}" result['data'].each do |app| puts "- #{app['name']} (#{app['embedCount']} embeds)" end ``` ```json 200 - Success theme={"dark"} { "data": [ { "name": "Customer Portal Analytics", "type": "embedded", "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-20T14:45:00Z", "embedCount": 3, "embeds": [ { "name": "Sales Dashboard Embed", "embedId": "sales-dashboard-123", "createdAt": "2024-01-15T11:00:00Z", "updatedAt": "2024-01-18T09:30:00Z" }, { "name": "Revenue Metrics Embed", "embedId": "revenue-metrics-456", "createdAt": "2024-01-16T14:15:00Z", "updatedAt": "2024-01-19T16:00:00Z" }, { "name": "Customer Overview", "embedId": "customer-overview-789", "createdAt": "2024-01-17T08:45:00Z", "updatedAt": "2024-01-20T11:20:00Z" } ] }, { "name": "Partner Dashboard", "type": "embedded", "createdAt": "2024-01-10T09:00:00Z", "updatedAt": "2024-01-15T12:30:00Z", "embedCount": 1, "embeds": [ { "name": "Partner Analytics", "embedId": "partner-analytics-001", "createdAt": "2024-01-10T10:00:00Z", "updatedAt": "2024-01-15T12:30:00Z" } ] } ] } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Data Apps retrieved successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | -------------------------------- | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide In **Settings** page, navigate to the **Service Tokens** section. Click the **"Generate Token"** button to create a new service token if you don't have one already. Make a GET request to retrieve all Data Apps: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` If you have many Data Apps, use pagination: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer service_token_xyz...' ``` Use the response to manage your Data Apps: ```javascript theme={"dark"} const dataApps = await listDataApps(); dataApps.data.forEach(app => { console.log(`Data App: ${app.name}`); console.log(` Type: ${app.type}`); console.log(` Embeds: ${app.embedCount}`); console.log(` Created: ${app.createdAt}`); app.embeds.forEach(embed => { console.log(` - ${embed.name} (${embed.embedId})`); }); }); ``` ## Next Steps Create new Data Apps for your organization Remove Data Apps you no longer need Generate API tokens for your Data Apps View API tokens for a specific Data App # List Datamarts Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-datamarts GET https://api.usedatabrain.com/api/v2/data-app/datamarts Retrieve a list of all datamarts in your data app with their configurations and access settings. Get a comprehensive list of all datamarts in your data app, including their configurations, datasources, and access settings. Useful for managing and auditing your data organization. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/datamarts`. The old endpoint `/api/v2/dataApp/datamarts` will be deprecated soon. Please update your integrations to use the new endpoint format. This endpoint returns all datamarts you have access to within the authenticated data app. The response includes metadata and access permissions for each datamart. Use the **`expandDetails`** parameter when you only need names and organization metadata and want a smaller payload: when `expandDetails` is `false`, **`datamartTables`** and **`datamartRelationships`** are omitted from each item (see [Query Parameters](#query-parameters)). ## Endpoint Formats ``` GET https://api.usedatabrain.com/api/v2/data-app/datamarts ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/datamart/list Content-Type: application/json { "isPagination": true, "pageNumber": 1, "expandDetails": false } ``` This endpoint still works but will be deprecated. **Content-Type:** `application/json`. The same **`getDatamartListSchema`** rules apply: optional **`isPagination`** (boolean), **`pageNumber`** (number), **`expandDetails`** (boolean). Send **`isPagination`** and **`pageNumber`** as JSON boolean and number — string values (for example `"true"`) usually fail Joi validation. For **`expandDetails`**, the route normalizes the body value before validation (booleans or string forms such as `"true"` / `"false"`); if **`expandDetails`** is omitted, **`getDatamartList`** defaults to expanded details, same as GET when the query parameter is omitted. Set it to `false` to omit **`datamartTables`** and **`datamartRelationships`** from each datamart. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ```bash Authentication theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters Enable pagination for the results. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"` (not boolean values). Page number to retrieve (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`, `"3"`). **GET only** (query string). Controls whether each datamart includes **`datamartTables`** (with **`datamartTableColumns`**) and **`datamartRelationships`** in the response. * If the **`expandDetails`** query parameter is **omitted**, the route passes **`expandDetails: true`** into **`getDatamartList`** (expanded). * If present, use the strings **`"true"`** or **`"false"`** (the server compares to `'true'`). When expanded details are **off** (`false`), each item still includes **`name`**, **`createdAt`**, **`updatedAt`**, **`datamartOrganization`**, and **`companyIntegration`**. **Legacy POST** accepts **`expandDetails`** in the JSON body; the route coerces it to a boolean before **`getDatamartListSchema`** runs (see the Legacy tab). Omit **`expandDetails`** to default to expanded details. **Note:** On GET, query parameters are strings — use `"true"` or `"false"`, not raw booleans. **Validation:** **`getDatamartListSchema`** allows optional **`isPagination`** (boolean), **`pageNumber`** (number), and **`expandDetails`** (boolean). On **GET** `/api/v2/data-app/datamarts`, query strings are mapped first: **`isPagination`** is `true` only when equal to **`"true"`**; **`pageNumber`** uses **`parseInt`** when present; **`expandDetails`** defaults to **`true`** when the query parameter is omitted, otherwise it is **`true`** only when the string equals **`"true"`**. On **POST** `/api/v2/dataApp/datamart/list`, **`isPagination`** and **`pageNumber`** are taken from the JSON body as-is; **`expandDetails`** is normalized from the body, then the same schema validates the combined payload inside **`getDatamartList`**. ## Response The **`datamartTables`** and **`datamartRelationships`** fields documented below are present **only when expanded details are enabled** (`expandDetails` not set to `false`). With `expandDetails=false`, rely on `name`, `createdAt`, `updatedAt`, `datamartOrganization`, and `companyIntegration` only. Array of datamart objects with their configuration details. The name of the datamart. Organization settings for the datamart. The tenancy level (`TABLE`, `DATABASE`, or `MULTI_DATABASE`). Schema name for the organization table. Table name for the organization. Type of the client column. Primary database name for `DATABASE` or `MULTI_DATABASE` tenancy. `null` when not set or when tenancy level is `TABLE`. Column name for client identification. Primary key column name. Integration details for the datamart. Name of the datasource integration. Array of tables included in the datamart. Schema name of the table. Name of the table. Label for the table providing a human-readable display name. Empty string when not set. Client/tenant column configured for this table. `null` when not set. Indicates whether the table is hidden in the datamart UI. Defaults to `false`. Array of columns in the table. Name of the column. Data type of the column. Alias for the column. Label for the column providing better readability. Indicates whether the column is hidden in the datamart UI. Defaults to `false`. Indicates whether this is a custom/calculated column defined by a SQL expression. `true` when the column was created with `isCustomColumn: true`. The SQL expression for custom columns. Empty string when `isCustomColumn` is `false`. Indicates whether timezone conversion is enabled for this column. When `true`, datetime values are converted at query time using the timezone specified in `params.timezone` of the guest token. Defaults to `false`. Default sort direction configured for the column. Returns `ASC`, `DESC`, or `null` when no default sort is configured. Array of relationships defined between tables in the datamart. Can be an empty array if no relationships are configured. Name of the parent table in the relationship. Column name in the parent table that participates in the relationship. Name of the child table in the relationship. Column name in the child table that participates in the relationship. Descriptive name for the relationship. The cardinality of the relationship. Can be: `ManyToMany`, `ManyToOne`, `OneToMany`, `OneToOne`, or `null` if not specified. The type of SQL join used. Can be: `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL JOIN`, or `null` if not specified. Error field, null when successful. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL - List without expanded tables & relationships theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts?expandDetails=false&isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1', { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Found datamarts:', data.data.length); ``` ```python Python theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/datamarts" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Found datamarts: {len(data['data'])}") ``` ```ruby Ruby theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts') params = { isPagination: 'true', pageNumber: '1' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Found datamarts: #{data['data'].length}" ``` ```java Java theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainDatamartAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String url = "https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" ) type DatamartListResponse struct { Data []interface{} `json:"data"` } func main() { url := "https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1" req, _ := http.NewRequest("GET", url, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var datamartResp DatamartListResponse json.NewDecoder(resp.Body).Decode(&datamartResp) fmt.Printf("Found datamarts: %d\n", len(datamartResp.Data)) } ``` ```php PHP theme={"dark"} [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Found datamarts: " . count($response['data']); ?> ``` ```json Success Response theme={"dark"} { "data": [ { "name": "sales-analytics", "datamartOrganization": { "tenancyLevel": "TABLE", "primaryDatabase": null, "schemaName": "public", "tableName": "organizations", "clientColumnType": "STRING", "tableClientNameColumn": "name", "tablePrimaryKeyColumn": "id" }, "companyIntegration": { "name": "postgres-prod" }, "datamartTables": [ { "schemaName": "public", "tableName": "customers", "label": "Customer Records", "clientColumn": "id", "isHide": false, "datamartTableColumns": [ { "columnName": "id", "datatype": "integer", "alias": "customer_id", "label": "Customer ID", "isHide": false, "isCustomColumn": false, "sql": "", "isApplyTimezone": false, "defaultSort": "ASC" }, { "columnName": "name", "datatype": "varchar", "alias": "customer_name", "label": "Customer Name", "isHide": false, "isCustomColumn": false, "sql": "", "isApplyTimezone": false, "defaultSort": null }, { "columnName": "created_at", "datatype": "timestamp", "alias": "created_at", "label": "Created At", "isHide": false, "isCustomColumn": false, "sql": "", "isApplyTimezone": true, "defaultSort": "DESC" } ] } ] } ], "datamartRelationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] } ], "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Missing or invalid data app", "status": 400 } } ``` ## Error Codes **Missing or invalid data app** - Check your API key and data app configuration **Unexpected failure** - Internal server error occurred ## HTTP Status Code Summary | Status Code | Description | | ----------- | --------------------------------------------------------------- | | 200 | **OK** - Request successful | | 400 | **Bad Request** - Invalid request parameters or missing API key | | 401 | **Unauthorized** - Invalid or expired API token | | 500 | **Internal Server Error** - Unexpected server error | ## Possible Errors | Code | Message | HTTP Status | | ---------------------------- | --------------------------- | ----------- | | INVALID\_DATA\_APP\_API\_KEY | Missing or invalid data app | 400 | | INTERNAL\_SERVER\_ERROR | Unexpected failure | 500 | ## Usage Examples ### Basic Usage ```javascript theme={"dark"} // Get all datamarts const datamarts = await listDatamarts(); console.log(`Total datamarts: ${datamarts.data.length}`); ``` ### With Pagination ```javascript theme={"dark"} // Get first page of datamarts const datamarts = await listDatamarts({ isPagination: true, pageNumber: 1 }); console.log(`Page 1 datamarts: ${datamarts.data.length}`); ``` ### Processing Results ```javascript theme={"dark"} // Process each datamart const datamarts = await listDatamarts(); datamarts.data.forEach(datamart => { console.log(`Datamart: ${datamart.name}`); console.log(`Tables: ${datamart.datamartTables.length}`); console.log(`Datasource: ${datamart.companyIntegration.name}`); }); ``` ## Best Practices Use pagination for data apps with many datamarts Cache datamart lists to reduce API calls Always handle API errors gracefully Monitor API usage and response times ## Quick Start Guide For detailed instructions, see the [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) guide. Make a simple request to see all your datamarts: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Note: You can add query parameters for pagination if needed. If you have many datamarts, enable pagination using query parameters: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Use the datamart information for embed configurations: ```javascript theme={"dark"} const datamarts = await listDatamarts(); datamarts.data.forEach(datamart => { console.log(`Datamart: ${datamart.name}`); console.log(`Tables: ${datamart.datamartTables.length}`); }); ``` ## Next Steps Create new datamarts for your data app Remove datamarts you no longer need Create embeddable configurations for your datamarts Generate secure tokens for embedded access # List Datasources Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-datasources GET https://api.usedatabrain.com/api/v2/datasource Retrieve a list of all datasources in your organization. Supports optional pagination for large datasets. Get a list of all datasources configured in your organization. Useful for managing datasources, verifying configurations, and identifying datasource names for use in other APIs. This endpoint returns all datasources you have access to within your organization. The response includes only the datasource names for security reasons - full credentials are never returned. ## Endpoint ``` GET https://api.usedatabrain.com/api/v2/datasource ``` ## Self-hosted Databrain Endpoint ``` GET /api/v2/datasource ``` ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. ```bash Authentication theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/datasource?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters Enable pagination for the results. Pass `"true"` to enable pagination with a limit of 10 datasources per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"` (not boolean values). Page number to retrieve (1-based). Only used when `isPagination` is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`, `"3"`). * First page is `"1"` (not `"0"`) * Each page returns up to 10 datasources * Only effective when `isPagination` is `"true"` ## Response Array of datasource objects. Each object contains only the datasource name for security reasons. The name of the datasource. This name can be used in other APIs to reference the datasource. Error field, null when successful. Not included in successful responses. ## Examples ```bash cURL - Without Pagination theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL - With Pagination theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/datasource?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js theme={"dark"} // List all datasources const response = await fetch('https://api.usedatabrain.com/api/v2/datasource', { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); if (data.error) { console.error('Error:', data.error); } else { console.log('Found datasources:', data.data.length); data.data.forEach(datasource => { console.log('-', datasource.name); }); } ``` ```javascript Node.js - With Pagination theme={"dark"} // List datasources with pagination const pageNumber = 1; const response = await fetch( `https://api.usedatabrain.com/api/v2/datasource?isPagination=true&pageNumber=${pageNumber}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); const data = await response.json(); console.log(`Page ${pageNumber} datasources:`, data.data.length); ``` ```python Python theme={"dark"} import requests # List all datasources response = requests.get( 'https://api.usedatabrain.com/api/v2/datasource', headers={ 'Authorization': 'Bearer dbn_live_abc123...' } ) data = response.json() if data.get('error'): print('Error:', data['error']) else: print(f'Found {len(data["data"])} datasources:') for datasource in data['data']: print(f" - {datasource['name']}") ``` ```python Python - With Pagination theme={"dark"} import requests # List datasources with pagination url = "https://api.usedatabrain.com/api/v2/datasource" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Page 1 datasources: {len(data['data'])}") ``` ```json Success Response theme={"dark"} { "data": [ { "name": "production-postgres" }, { "name": "analytics-snowflake" }, { "name": "warehouse-bigquery" } ] } ``` ```json Success Response - Empty List theme={"dark"} { "data": [] } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid pagination parameters", "status": 400 } } ``` ```json Error Response (401) theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "AUTHENTICATION_ERROR", "status": 401 } } ``` ```json Error Response (500) theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal server error", "status": 500 } } ``` ## Error Codes | Error Code | HTTP Status | Description | | ----------------------- | ----------- | -------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Invalid pagination parameters | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error occurred | ## Next Steps Create new datasources for your organization Update existing datasource credentials Remove datasources you no longer need Sync datasource schema after changes # List All Embeds Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-embed GET https://api.usedatabrain.com/api/v2/data-app/embeds Fetch a list of all embeds created by the authenticated data app. Get a comprehensive list of all embed configurations created by your data app, including both dashboard and metric embeds with their associated metadata. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/embeds`. The old endpoint `/api/v2/dataApp/embeds` will be deprecated soon. Please update your integrations to use the new endpoint format. This endpoint returns all embeds you have access to within the authenticated data app. The response includes embed IDs, types, and associated dashboard/metric information. ## Endpoint Formats ``` GET https://api.usedatabrain.com/api/v2/data-app/embeds ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/embed/list Content-Type: application/json { "isPagination": true, "pageNumber": 1 } ``` This endpoint still works but will be deprecated. Uses POST method with JSON body. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters Whether to paginate results. Pass `"true"` to enable pagination with a limit of 10 per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number to retrieve (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). Optional client ID to filter embeds. When provided, only returns dashboard embeds where the dashboard was created by the specified client. ## Response Array of embed objects with their configuration details. Unique identifier for the embed configuration. Type of embed: "dashboard" or "metric". The human-readable name of the embed configuration. This is the name set when creating or renaming the embed configuration. Dashboard information (present when embedType is "dashboard", null otherwise). Unique identifier for the external dashboard. Dashboard metadata information. Name of the dashboard. Metric information (present when embedType is "metric", null otherwise). Unique identifier for the external metric. Name of the metric. Consolidated metadata object containing key embed information for easy access. Unique identifier for the embed configuration. The human-readable name of the embed configuration. Type of embed: "dashboard" or "metric". Name of the data app associated with this embed. Unique identifier for the metric (present when embedType is "metric", null otherwise). Unique identifier for the dashboard (present when embedType is "dashboard", null otherwise). ISO 8601 formatted timestamp indicating when the embed configuration was created. ISO 8601 formatted timestamp indicating when the embed configuration was last updated. Error field, null when successful. Not included in successful responses. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds?isPagination=true&pageNumber=1', { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Found embeds:', data.data.length); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/embeds" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Found embeds: {len(data['data'])}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/embeds') params = { isPagination: 'true', pageNumber: '1' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Found embeds: #{data['data'].length}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainEmbedAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String url = "https://api.usedatabrain.com/api/v2/data-app/embeds" + "?isPagination=true&pageNumber=1"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type EmbedListResponse struct { Data []interface{} `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/embeds" params := url.Values{} params.Add("isPagination", "true") params.Add("pageNumber", "1") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var embedResp EmbedListResponse json.NewDecoder(resp.Body).Decode(&embedResp) fmt.Printf("Found embeds: %d\n", len(embedResp.Data)) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'true', 'pageNumber' => '1' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/embeds?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Found embeds: " . count($response['data']); ?> ``` ```json Success Response theme={"dark"} { "data": [ { "embedId": "dashboard-123", "embedType": "dashboard", "name": "Sales Dashboard Embed", "externalDashboard": { "externalDashboardId": "dashboard-uuid-456", "metadata": { "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-20T14:45:00Z" }, "name": "Sales Analytics Dashboard" }, "externalMetric": null, "embedMetadata": { "embedId": "dashboard-123", "name": "Sales Dashboard Embed", "embedType": "dashboard", "dataAppName": "Production Data App", "metricId": null, "dashboardId": "dashboard-uuid-456", "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-20T14:45:00Z" } }, { "embedId": "metric-456", "embedType": "metric", "name": "Revenue Metric Embed", "externalDashboard": null, "externalMetric": { "metricId": "metric-uuid-789", "name": "Monthly Revenue" }, "embedMetadata": { "embedId": "metric-456", "name": "Revenue Metric Embed", "embedType": "metric", "dataAppName": "Production Data App", "metricId": "metric-uuid-789", "dashboardId": null, "createdAt": "2024-01-16T08:15:00Z", "updatedAt": "2024-01-18T12:30:00Z" } } ], "error": null } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ## Error Codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | --------------------------- | | `INVALID_DATA_APP_API_KEY` | 400 | Missing or invalid data app | | `INTERNAL_SERVER_ERROR` | 500 | Server error occurred | ## Quick Start Guide For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). Get all your embed configurations: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Note: You can add query parameters for pagination or filtering if needed. If you have many embed configurations, use pagination with query parameters: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Use the embed information to manage your configurations: ```javascript theme={"dark"} const embeds = await listEmbeds(); embeds.data.forEach(embed => { console.log(`Embed ID: ${embed.embedId}`); console.log(`Embed Name: ${embed.name}`); console.log(`Type: ${embed.embedType}`); // Access timestamps and IDs from embedMetadata console.log(`Created: ${embed.embedMetadata.createdAt}`); console.log(`Updated: ${embed.embedMetadata.updatedAt}`); console.log(`Data App: ${embed.embedMetadata.dataAppName}`); if (embed.embedType === 'dashboard' && embed.externalDashboard) { console.log(`Dashboard ID: ${embed.externalDashboard.externalDashboardId}`); console.log(`Dashboard: ${embed.externalDashboard.name}`); console.log(`Dashboard ID (from metadata): ${embed.embedMetadata.dashboardId}`); } else if (embed.embedType === 'metric' && embed.externalMetric) { console.log(`Metric ID: ${embed.externalMetric.metricId}`); console.log(`Metric: ${embed.externalMetric.name}`); console.log(`Metric ID (from metadata): ${embed.embedMetadata.metricId}`); } }); ``` ## Next Steps Learn how to create new embed configurations Modify existing embed access settings Remove embed configurations you no longer need Query data from your embedded metrics # List Schedule Reports by Embed Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-schedule-reports-by-embed GET https://api.usedatabrain.com/api/v2/data-app/embeds/reports?embedId={id}&clientId={client_xyz789}&isPagination=true&pageNumber=1 Retrieve scheduled email reports for a specific embed configuration, with support for pagination and filtering by client or user identifier. Get a list of scheduled email reports associated with a specific embed configuration. This endpoint allows you to retrieve all scheduled reports for an embed, with optional filtering by client ID or user identifier, and supports pagination for large result sets. This endpoint returns scheduled email reports that have been configured for the specified embed. Reports are filtered based on the embed's data app and can be further filtered by client ID or user identifier. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/embeds/reports \ --header 'Authorization: Bearer dbn_live_...' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters The embed configuration ID to fetch scheduled reports for. This identifies which embedded dashboard's scheduled reports you want to retrieve. * Created when you configure an embed via the [Create Embed API](/developer-docs/helpers/api-reference/create-embed) * Retrieved via the [List Embeds API](/developer-docs/helpers/api-reference/list-embed) * Available in your DataBrain dashboard embed settings Optional client identifier for filtering reports. When provided, only returns scheduled reports associated with the specified client. * When `clientId` is provided: Returns only reports configured for that specific client * When omitted: Returns all scheduled reports for the embed (across all clients) * Useful for multi-tenant applications where each client has their own scheduled reports Enable pagination to limit the number of results returned. Pass `"true"` to enable pagination with a limit of 10 reports per page. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"`. Page number for pagination (1-based). Only used when isPagination is `"true"`. Must be a numeric string (e.g., `"1"`, `"2"`). **Default:** If pagination is enabled and pageNumber is not provided, defaults to page 1. Filter reports by the user identifier who created them. When provided, only returns scheduled reports created by the specified user. * When `userIdentifier` is provided: Returns only reports where `createdByIdentifier` matches * When omitted: Returns all scheduled reports for the embed (regardless of creator) * Useful for showing "My Scheduled Reports" views in your application ## Response Array of scheduled email report objects for the specified embed. Unique identifier for the scheduled email report. The subject line of the scheduled email report. Array of charts/metrics included in this scheduled report. The unique identifier of the metric included in the report. Configuration object defining when and how often the report is scheduled to be sent. Contains scheduling details such as frequency (daily, weekly, monthly), time of day, timezone, and other scheduling parameters. ISO 8601 timestamp indicating when the scheduled report was created. ISO 8601 timestamp indicating when the scheduled report was last updated. The client identifier associated with this scheduled report. This is extracted from the guest token used when creating the report. The embed configuration ID this scheduled report is associated with. The identifier of the user who created this scheduled report, or `null` if not specified. * Non-null value: Indicates a user-created scheduled report with the creator's identifier * `null`: Indicates a system-created or admin-created scheduled report Error object returned only when the request fails. Not present in successful responses. Machine-readable error code for programmatic handling. Human-readable error message explaining what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/embeds/reports?embedId=embed_abc123&clientId=client_xyz789&isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js theme={"dark"} const params = new URLSearchParams({ embedId: 'embed_abc123', clientId: 'client_xyz789', isPagination: 'true', pageNumber: '1' }); const response = await fetch(`https://api.usedatabrain.com/api/v2/data-app/embeds/reports?${params}`, { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const data = await response.json(); console.log('Scheduled reports:', data.data); ``` ```python Python theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/dataApp/embeds/reports" headers = { "Authorization": "Bearer dbn_live_abc123..." } params = { "embedId": "embed_abc123", "clientId": "client_xyz789", "isPagination": "true", "pageNumber": "1" } response = requests.get(url, headers=headers, params=params) data = response.json() print(f"Scheduled reports: {data['data']}") ``` ```ruby Ruby theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/embeds/reports') params = { embedId: 'embed_abc123', clientId: 'client_xyz789', isPagination: 'true', pageNumber: '1' } uri.query = URI.encode_www_form(params) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) data = JSON.parse(response.body) puts "Scheduled reports: #{data['data']}" ``` ```java Java theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class DataBrainScheduleReportsAPI { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String url = "https://api.usedatabrain.com/api/v2/data-app/embeds/reports" + "?embedId=embed_abc123&clientId=client_xyz789&isPagination=true&pageNumber=1"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(url)) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go theme={"dark"} package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type ScheduleReport struct { Subject string `json:"subject"` ScheduleEmailReportCharts []struct { ExternalMetric struct { MetricID string `json:"metricId"` } `json:"externalMetric"` } `json:"scheduleEmailReportCharts"` TimeConfigurations interface{} `json:"timeConfigurations"` CreatedAt string `json:"createdAt"` UpdatedAt string `json:"updatedAt"` ClientID string `json:"clientId"` EmbedID string `json:"embedId"` CreatedByIdentifier *string `json:"createdByIdentifier"` } type ScheduleReportResponse struct { Data []ScheduleReport `json:"data"` Error interface{} `json:"error"` } func main() { baseURL := "https://api.usedatabrain.com/api/v2/data-app/embeds/reports" params := url.Values{} params.Add("embedId", "embed_abc123") params.Add("clientId", "client_xyz789") params.Add("isPagination", "true") params.Add("pageNumber", "1") fullURL := fmt.Sprintf("%s?%s", baseURL, params.Encode()) req, _ := http.NewRequest("GET", fullURL, nil) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") client := &http.Client{} resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var reportResp ScheduleReportResponse json.NewDecoder(resp.Body).Decode(&reportResp) fmt.Printf("Scheduled reports: %+v\n", reportResp.Data) } ``` ```php PHP theme={"dark"} 'embed_abc123', 'clientId' => 'client_xyz789', 'isPagination' => 'true', 'pageNumber' => '1' ]); $url = 'https://api.usedatabrain.com/api/v2/data-app/embeds/reports?' . $params; $options = [ 'http' => [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $result = file_get_contents($url, false, $context); $response = json_decode($result, true); echo "Scheduled reports: " . print_r($response['data'], true); ?> ``` ```json Success Response theme={"dark"} { "data": [ { "id": "report-1", "subject": "Daily Sales Report", "scheduleEmailReportCharts": [ { "externalMetric": { "metricId": "metric_revenue_123" } }, { "externalMetric": { "metricId": "metric_orders_456" } } ], "timeConfigurations": { "frequency": "daily", "time": "09:00", "timezone": "UTC" }, "createdAt": "2024-01-15T10:30:00Z", "updatedAt": "2024-01-20T14:22:00Z", "clientId": "client_xyz789", "embedId": "embed_abc123", "createdByIdentifier": "user_abc123" }, { "id": "report-2", "subject": "Weekly Summary Report", "scheduleEmailReportCharts": [ { "externalMetric": { "metricId": "metric_users_789" } } ], "timeConfigurations": { "frequency": "weekly", "day": "monday", "time": "08:00", "timezone": "UTC" }, "createdAt": "2024-01-10T08:15:00Z", "updatedAt": "2024-01-10T08:15:00Z", "clientId": "client_xyz789", "embedId": "embed_abc123", "createdByIdentifier": null } ] } ``` ```json Empty Results Response theme={"dark"} { "data": [] } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_EMBED_ID", "message": "invalid embed id, embed id not found for given data app" } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"embedId\" is required" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------------------------------------------------- | | `200` | **OK** - Scheduled reports retrieved successfully | | `400` | **Bad Request** - Invalid request parameters, missing required fields, invalid API key, or embed ID not found | | `500` | **Internal Server Error** - Server error occurred while processing the request | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------------------------------ | | `INVALID_DATA_APP_API_KEY` | 400 | Invalid or expired API key, or data app not found | | `INVALID_EMBED_ID` | 400 | Embed ID not found for the given data app | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid required parameters (e.g., embedId is required) | | `INTERNAL_SERVER_ERROR` | 500 | An unexpected error occurred on the server | ## Filtering and Pagination ### Client Filtering When `clientId` is provided, the API returns only scheduled reports associated with that specific client: ```javascript theme={"dark"} // Get reports for a specific client const clientReports = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123&clientId=client_A`); // Get all reports for the embed (across all clients) const allReports = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123`); ``` ### User Filtering When `userIdentifier` is provided, the API returns only scheduled reports created by that user: ```javascript theme={"dark"} // Get reports created by a specific user const userReports = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123&userIdentifier=user_abc`); // Get all reports (regardless of creator) const allReports = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123`); ``` ### Combined Filtering You can combine `clientId` and `userIdentifier` to filter reports by both client and creator: ```javascript theme={"dark"} // Get reports for a specific client created by a specific user const filteredReports = await fetch( `/api/v2/data-app/embeds/reports?embedId=embed_123&clientId=client_A&userIdentifier=user_abc` ); ``` ### Pagination When pagination is enabled, results are limited to 10 reports per page: ```javascript theme={"dark"} // Get first page (reports 1-10) const page1 = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123&isPagination=true&pageNumber=1`); // Get second page (reports 11-20) const page2 = await fetch(`/api/v2/data-app/embeds/reports?embedId=embed_123&isPagination=true&pageNumber=2`); ``` ## Use Cases ### 1. Display Scheduled Reports in Dashboard Show all scheduled reports configured for an embed in your application's settings page: ```javascript theme={"dark"} async function loadScheduledReports(embedId) { const response = await fetch( `https://api.usedatabrain.com/api/v2/data-app/embeds/reports?embedId=${embedId}`, { headers: { 'Authorization': `Bearer ${apiToken}` } } ); const { data } = await response.json(); return data; // Display in UI } ``` ### 2. Client-Specific Report Management Allow clients to view and manage only their own scheduled reports: ```javascript theme={"dark"} async function getClientReports(embedId, clientId) { const response = await fetch( `https://api.usedatabrain.com/api/v2/data-app/embeds/reports?embedId=${embedId}&clientId=${clientId}`, { headers: { 'Authorization': `Bearer ${apiToken}` } } ); const { data } = await response.json(); return data; } ``` ### 3. User-Specific Report View Show users only the reports they created: ```javascript theme={"dark"} async function getUserReports(embedId, userIdentifier) { const response = await fetch( `https://api.usedatabrain.com/api/v2/data-app/embeds/reports?embedId=${embedId}&userIdentifier=${userIdentifier}`, { headers: { 'Authorization': `Bearer ${apiToken}` } } ); const { data } = await response.json(); return data; } ``` # List Workspaces Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/list-workspaces GET https://api.usedatabrain.com/api/v2/workspace Retrieve all workspaces in your organization with optional pagination support for efficient data retrieval. Retrieve a list of all workspaces in your organization. This endpoint supports pagination to efficiently handle large numbers of workspaces. Use pagination when you have many workspaces to improve response times and reduce data transfer. The default page limit is 10 workspaces per page. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Query Parameters Enable pagination to retrieve workspaces in batches. Pass `"true"` to enable pagination. **Note:** Query parameters are passed as strings. Use `"true"` or `"false"` (not boolean values). * `"true"`: Enable pagination with page-based retrieval (10 items per page) * `"false"` (default): Return all workspaces in a single response - Use pagination when you have more than 50 workspaces - Improves response times for large datasets - Reduces memory usage in your application - Each page returns up to 10 workspaces The page number to retrieve when pagination is enabled. Must be a numeric string (e.g., `"1"`, `"2"`, `"3"`). **Note:** This parameter is only used when `isPagination` is set to `"true"`. * Pages start at 1 (first page) * Each page contains up to 10 workspaces * Returns empty array if page number exceeds available pages ## Response Array of workspace objects. Returns empty array if no workspaces exist or page number exceeds available pages. The name of the workspace. Error object if the request failed, otherwise `null` for successful requests. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - All Workspaces theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/workspace' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL - With Pagination theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/workspace?isPagination=true&pageNumber=1' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL - Second Page theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/workspace?isPagination=true&pageNumber=2' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```javascript Node.js - All Workspaces icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace', { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const result = await response.json(); console.log(result.data); // Array of all workspaces ``` ```javascript Node.js - With Pagination icon="fa-brands fa-node-js" theme={"dark"} async function fetchAllWorkspaces() { let allWorkspaces = []; let pageNumber = 1; let hasMorePages = true; while (hasMorePages) { const response = await fetch( `https://api.usedatabrain.com/api/v2/workspace?isPagination=true&pageNumber=${pageNumber}`, { headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); const result = await response.json(); if (result.data && result.data.length > 0) { allWorkspaces = allWorkspaces.concat(result.data); pageNumber++; } else { hasMorePages = false; } } return allWorkspaces; } const workspaces = await fetchAllWorkspaces(); console.log(`Total workspaces: ${workspaces.length}`); ``` ```python Python - All Workspaces icon="fa-brands fa-python" theme={"dark"} import requests response = requests.get( 'https://api.usedatabrain.com/api/v2/workspace', headers={ 'Authorization': 'Bearer dbn_live_abc123...' } ) result = response.json() workspaces = result['data'] print(f"Total workspaces: {len(workspaces)}") ``` ```python Python - With Pagination icon="fa-brands fa-python" theme={"dark"} import requests def fetch_all_workspaces(api_key): all_workspaces = [] page_number = 1 has_more_pages = True while has_more_pages: response = requests.get( 'https://api.usedatabrain.com/api/v2/workspace', params={ 'isPagination': 'true', 'pageNumber': page_number }, headers={ 'Authorization': f'Bearer {api_key}' } ) result = response.json() if result['data'] and len(result['data']) > 0: all_workspaces.extend(result['data']) page_number += 1 else: has_more_pages = False return all_workspaces workspaces = fetch_all_workspaces('dbn_live_abc123...') print(f"Total workspaces: {len(workspaces)}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/workspace') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Get.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' response = http.request(request) result = JSON.parse(response.body) puts "Total workspaces: #{result['data'].length}" result['data'].each do |workspace| puts "- #{workspace['name']}" end ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class ListWorkspaces { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/workspace")) .header("Authorization", "Bearer dbn_live_abc123...") .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go - With Pagination icon="fa-brands fa-golang" theme={"dark"} package main import ( "encoding/json" "fmt" "io" "net/http" ) type WorkspaceResponse struct { Data []Workspace `json:"data"` Error interface{} `json:"error"` } type Workspace struct { Name string `json:"name"` } func fetchAllWorkspaces(apiKey string) ([]Workspace, error) { var allWorkspaces []Workspace pageNumber := 1 for { url := fmt.Sprintf( "https://api.usedatabrain.com/api/v2/workspace?isPagination=true&pageNumber=%d", pageNumber, ) req, _ := http.NewRequest("GET", url, nil) req.Header.Set("Authorization", "Bearer "+apiKey) client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, err } body, _ := io.ReadAll(resp.Body) resp.Body.Close() var result WorkspaceResponse json.Unmarshal(body, &result) if len(result.Data) == 0 { break } allWorkspaces = append(allWorkspaces, result.Data...) pageNumber++ } return allWorkspaces, nil } func main() { workspaces, _ := fetchAllWorkspaces("dbn_live_abc123...") fmt.Printf("Total workspaces: %d\n", len(workspaces)) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} [ 'header' => 'Authorization: Bearer dbn_live_abc123...', 'method' => 'GET' ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); echo "Total workspaces: " . count($result['data']) . "\n"; foreach ($result['data'] as $workspace) { echo "- " . $workspace['name'] . "\n"; } ?> ``` ```json 200 - Success (Multiple Workspaces) theme={"dark"} { "data": [ { "name": "Sales Analytics" }, { "name": "Customer Insights" }, { "name": "Marketing Dashboard" } ], "error": null } ``` ```json 200 - Success (Empty) theme={"dark"} { "data": [], "error": null } ``` ```json 200 - Success (First Page) theme={"dark"} { "data": [ { "name": "Workspace 1" }, { "name": "Workspace 2" }, { "name": "Workspace 3" }, { "name": "Workspace 4" }, { "name": "Workspace 5" }, { "name": "Workspace 6" }, { "name": "Workspace 7" }, { "name": "Workspace 8" }, { "name": "Workspace 9" }, { "name": "Workspace 10" } ], "error": null } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal Server Error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Workspaces retrieved successfully | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | Solution | | -------------------------- | ----------- | --------------- | --------------------------------------------------------- | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | Verify your API key is correct and has proper permissions | | `INTERNAL_SERVER_ERROR` | 500 | Server error | Contact support if error persists | ## Pagination Details When `isPagination` is set to `true`: * Each page returns up to **10 workspaces** * Pages are 1-indexed (first page is `pageNumber=1`) * An empty array is returned when you've reached the end * Use this to implement "load more" or infinite scroll patterns **Example flow:** 1. Request page 1 → Returns 10 workspaces 2. Request page 2 → Returns 10 more workspaces 3. Request page 3 → Returns 5 workspaces 4. Request page 4 → Returns empty array (no more data) **Use pagination when:** * You have more than 50 workspaces * Building user interfaces with "load more" functionality * Implementing infinite scroll * Optimizing for mobile or slow connections **Skip pagination when:** * You have fewer than 20 workspaces * You need all workspace data for processing * Implementing search or filter functionality client-side * **Cache results**: Store workspace lists client-side to reduce API calls * **Handle empty pages**: Check for empty arrays to detect the last page * **Show loading states**: Display loading indicators between page requests * **Error handling**: Implement retry logic for failed requests * **Rate limiting**: Respect API rate limits when fetching multiple pages ## Quick Start: Implement Pagination For large workspace lists, implement pagination to efficiently fetch results page by page: ```javascript theme={"dark"} async function loadWorkspacePage(pageNumber) { const response = await fetch( `https://api.usedatabrain.com/api/v2/workspace?isPagination=true&pageNumber=${pageNumber}`, { headers: { 'Authorization': 'Bearer dbn_live_abc123...' } } ); return await response.json(); } // Load first page const page1 = await loadWorkspacePage(1); ``` Implement a "Load More" button that increments the page number on each click to fetch additional workspaces. # Proxy Authentication Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/proxy-authentication Configure a proxy server to securely forward requests to your Databrain backend with authentication. This page explains how to: 1. Create YOUR OWN proxy server that forwards requests to your Databrain backend 2. Configure the proxy to validate requests and add authentication headers Your proxy acts as a secure gateway between your frontend and the Databrain backend. Proxy authentication lets you host a secure intermediary server that validates incoming requests and forwards them to your Databrain backend. This approach keeps your plugin tokens secure on your server, never exposing them to the client. **Enhanced Security:** With proxy authentication, your frontend never handles plugin tokens. Your proxy validates requests and adds the required authentication before forwarding to Databrain. ## How Proxy Authentication Works ```mermaid theme={"dark"} sequenceDiagram participant Client as Client (Browser) participant Proxy as Your Proxy Server participant Backend as Databrain Backend Client->>Proxy: Request with X-Proxy-Auth-Key (or X-Authorization) Proxy->>Proxy: Validate & add X-Plugin-Token Proxy->>Backend: Forward request (method + body + headers) Backend-->>Proxy: Response (status + body + headers) Proxy-->>Client: Forward response exactly ``` Your frontend sends a request to your proxy server with the `X-Proxy-Auth-Key: ` or `X-Authorization: ` header for validation. Your proxy validates the `X-Proxy-Auth-Key: ` or `X-Authorization: ` header. If invalid or missing, return an error response. Your proxy constructs the upstream URL, adds the `X-Plugin-Token` header, and forwards the request to your Databrain backend exactly as received. Your proxy returns the Databrain backend response to the client exactly as received (status code, body, and headers). ## What Your Proxy Must Do Your proxy can be built on **any backend**: Node.js, Express, FastAPI, Python, Go, Lambda, Cloudflare Worker, etc. It must receive requests from your frontend and forward them to your Databrain backend exactly as-is, with required headers added. ### 1. Read the Incoming Request Capture all parts of the incoming request: * Path * Query parameters * HTTP method * Headers * **Body** (JSON, text, or binary/raw) Body must **not** be modified. Preserve the raw content if it's binary (zip, pdf, excel, etc.) or text/JSON for other API calls. ### 2. Validate Proxy Authentication Your proxy must read and validate either the `X-Proxy-Auth-Key` header or the `X-Authorization` header: ``` X-Proxy-Auth-Key: ``` Or: ``` X-Authorization: ``` Compare with your stored secret value. If missing or invalid, return an error: ```json theme={"dark"} { "error": { "message": "missing or invalid proxy auth key" } } ``` Return appropriate HTTP status (401 or 403). ### 3. Forward Request to Databrain Backend #### Construct Upstream URL ``` /? ``` #### Forward Original Method Forward the exact HTTP method: GET, POST, PUT, PATCH, DELETE. #### Forward Body Exactly Do not modify the request payload in any way. #### Required Upstream Headers Send these headers to your Databrain backend: | Header | Description | | ------------------ | -------------------------------------- | | `Accept` | Forward from incoming request | | `Accept-Language` | Forward from incoming request | | `User-Agent` | Forward from incoming request | | `Content-Type` | Forward if present in incoming request | | `X-Plugin-Origin` | Forward if provided by frontend | | `X-Proxy-Auth-Key` | Forward original value (if provided) | | `X-Authorization` | Forward original value (if provided) | | `X-Proxy-Auth-Url` | Forward original value | | `X-Plugin-Token` | **Your plugin token (added by proxy)** | | `Origin` | Forward original value | ### 4. Return Response Exactly Return **exactly** what the Databrain backend returns: * Status code * Response body (binary or text, do not transform) * Response headers **Binary responses** (zip, pdf, xlsx) must be forwarded as-is. Do not convert binary content to text. ## About X-Plugin-Token The `X-Plugin-Token` header authenticates your requests with the Databrain backend. You can provide this token in two ways: 1. **A saved token** - Use a pre-generated guest token stored in your environment 2. **Generate on demand** - Call the [Databrain Guest Token API](/developer-docs/helpers/api-reference/token) to generate tokens dynamically ## Error Response Format Every error your proxy returns should follow this format: ```json theme={"dark"} { "error": { "message": "description of the error" } } ``` **Examples:** ```json theme={"dark"} { "error": { "message": "missing or invalid proxy auth key" } } ``` ```json theme={"dark"} { "error": { "message": "upstream fetch failed" } } ``` ## Requirements Summary * Keep method, path, and query unchanged * Preserve body type: JSON, text, or binary * Pass all required headers (including `Origin`) * Add `X-Plugin-Token` header * Validate `X-Proxy-Auth-Key` **or** `X-Authorization` before forwarding * Use correct error format * Return upstream response exactly (status, body, headers) * Forward binary responses (zip, pdf, xlsx) as-is * Do not rewrite paths * Do not remove fields from body * Do not add custom fields to body * Do not modify query parameters * Do not transform the response ## Implementation Examples ```typescript theme={"dark"} import express from "express"; import fetch from "node-fetch"; import bodyParser from "body-parser"; const app = express(); app.use(bodyParser.raw({ type: "*/*" })); // preserve raw body // --- Environment variables --- const PROXY_AUTH_KEY = process.env.PROXY_AUTH_KEY; // secret key for validating requests const SELFHOSTED_BACKEND_URL = process.env.SELFHOSTED_BACKEND_URL; // your Databrain backend const GUEST_TOKEN = process.env.GUEST_TOKEN; // plugin token (saved or generated via API) app.all('/proxy-auth/*', async (req, res) => { try { // --- Extract path and query --- const upstreamPath = req.path.replace(/^\/proxy-auth/, '') || '/'; const queryString = req.originalUrl.split('?')[1] || ''; const upstreamUrl = `${SELFHOSTED_BACKEND_URL}${upstreamPath}${queryString ? `?${queryString}` : ''}`; const method = req.method; const incomingHeaders = req.headers || {}; // --- Handle preflight OPTIONS request --- if (method === 'OPTIONS') { return res.status(204).end(); } // --- Validate proxy key --- const incomingProxyKey = incomingHeaders['x-proxy-auth-key'] || incomingHeaders['x-authorization']; if (!incomingProxyKey || incomingProxyKey !== PROXY_AUTH_KEY) { return res.status(401).json({ error: { message: 'missing or invalid proxy auth key' }, }); } // --- Build upstream headers --- const upstreamHeaders: Record = { Accept: incomingHeaders['accept'] || '*/*', 'Accept-Language': incomingHeaders['accept-language'] || 'en-US', 'User-Agent': incomingHeaders['user-agent'] || 'Mozilla/5.0', 'X-Plugin-Token': GUEST_TOKEN, }; if (incomingHeaders['content-type']) { upstreamHeaders['Content-Type'] = incomingHeaders['content-type']; } if (incomingHeaders['x-plugin-origin']) { upstreamHeaders['X-Plugin-Origin'] = incomingHeaders['x-plugin-origin']; } if (incomingHeaders['x-proxy-auth-url']) { upstreamHeaders['X-Proxy-Auth-Url'] = incomingHeaders['x-proxy-auth-url']; } if (incomingHeaders['x-proxy-auth-key']) { upstreamHeaders['X-Proxy-Auth-Key'] = incomingHeaders['x-proxy-auth-key']; } if (incomingHeaders['x-authorization']) { upstreamHeaders['X-Authorization'] = incomingHeaders['x-authorization']; } if (incomingHeaders['origin']) { upstreamHeaders['Origin'] = incomingHeaders['origin']; } // --- Prepare request body for non-GET/HEAD methods --- let upstreamBody; if (!['GET', 'HEAD'].includes(method)) { upstreamBody = req.is('application/json') ? JSON.stringify(req.body) : req.body; } // --- Forward request to backend --- let upstreamResponse; try { upstreamResponse = await fetch(upstreamUrl, { method, headers: upstreamHeaders, body: upstreamBody, }); } catch (err: any) { return res.status(502).json({ error: { message: 'upstream fetch failed' }, detail: err.message, }); } // --- Forward upstream headers as-is --- const outHeaders: Record = {}; upstreamResponse.headers.forEach((v, k) => (outHeaders[k] = v)); // --- Handle binary vs text responses --- const contentType = upstreamResponse.headers.get('content-type') || ''; if (contentType.startsWith('text/') || contentType.includes('json')) { const text = await upstreamResponse.text(); res.status(upstreamResponse.status).set(outHeaders).send(text); } else { const buffer = Buffer.from(await upstreamResponse.arrayBuffer()); res.status(upstreamResponse.status).set(outHeaders).send(buffer); } } catch (err: any) { return res.status(500).json({ error: { message: 'internal server error' }, detail: err.message, }); } }); // --- Start server --- app.listen(3000, () => { console.log('Proxy server running on port 3000'); }); ``` ```python theme={"dark"} from fastapi import FastAPI, Request, Response from fastapi.responses import JSONResponse import httpx import os app = FastAPI() # --- Environment variables --- PROXY_AUTH_KEY = os.getenv("PROXY_AUTH_KEY") # secret key for validating requests SELFHOSTED_BACKEND_URL = os.getenv("SELFHOSTED_BACKEND_URL") # your Databrain backend GUEST_TOKEN = os.getenv("GUEST_TOKEN") # plugin token (saved or generated via API) @app.api_route("/proxy-auth/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) async def proxy_handler(request: Request, path: str): try: method = request.method # --- Handle preflight OPTIONS request --- if method == "OPTIONS": return Response(status_code=204) # --- Validate proxy key --- incoming_proxy_key = request.headers.get("x-proxy-auth-key") or request.headers.get("x-authorization") if not incoming_proxy_key or incoming_proxy_key != PROXY_AUTH_KEY: return JSONResponse( status_code=401, content={"error": {"message": "missing or invalid proxy auth key"}} ) # --- Construct upstream URL --- query_string = str(request.query_params) upstream_url = f"{SELFHOSTED_BACKEND_URL}/{path}" if query_string: upstream_url += f"?{query_string}" # --- Build upstream headers --- upstream_headers = { "Accept": request.headers.get("accept", "*/*"), "Accept-Language": request.headers.get("accept-language", "en-US"), "User-Agent": request.headers.get("user-agent", "Mozilla/5.0"), "X-Plugin-Token": GUEST_TOKEN, } if content_type := request.headers.get("content-type"): upstream_headers["Content-Type"] = content_type if plugin_origin := request.headers.get("x-plugin-origin"): upstream_headers["X-Plugin-Origin"] = plugin_origin if proxy_auth_url := request.headers.get("x-proxy-auth-url"): upstream_headers["X-Proxy-Auth-Url"] = proxy_auth_url if proxy_auth_key := request.headers.get("x-proxy-auth-key"): upstream_headers["X-Proxy-Auth-Key"] = proxy_auth_key if x_authorization := request.headers.get("x-authorization"): upstream_headers["X-Authorization"] = x_authorization if origin := request.headers.get("origin"): upstream_headers["Origin"] = origin # --- Get request body --- body = await request.body() if method not in ["GET", "HEAD"] else None # --- Forward request to backend --- async with httpx.AsyncClient() as client: try: upstream_response = await client.request( method=method, url=upstream_url, headers=upstream_headers, content=body, ) except httpx.RequestError as e: return JSONResponse( status_code=502, content={"error": {"message": "upstream fetch failed"}, "detail": str(e)} ) # --- Forward upstream headers as-is --- out_headers = dict(upstream_response.headers) # Remove hop-by-hop headers for header in ["transfer-encoding", "connection", "keep-alive"]: out_headers.pop(header, None) # --- Handle binary vs text responses --- # Response.content is already bytes, works for both binary and text return Response( content=upstream_response.content, status_code=upstream_response.status_code, headers=out_headers, media_type=upstream_response.headers.get("content-type"), ) except Exception as e: return JSONResponse( status_code=500, content={"error": {"message": "internal server error"}, "detail": str(e)} ) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=3000) ``` ```python theme={"dark"} from flask import Flask, request, Response, jsonify import requests import os app = Flask(__name__) # --- Environment variables --- PROXY_AUTH_KEY = os.getenv("PROXY_AUTH_KEY") # secret key for validating requests SELFHOSTED_BACKEND_URL = os.getenv("SELFHOSTED_BACKEND_URL") # your Databrain backend GUEST_TOKEN = os.getenv("GUEST_TOKEN") # plugin token (saved or generated via API) @app.route("/proxy-auth/", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) def proxy_handler(path): try: method = request.method # --- Handle preflight OPTIONS request --- if method == "OPTIONS": return Response(status=204) # --- Validate proxy key --- incoming_proxy_key = request.headers.get("X-Proxy-Auth-Key") or request.headers.get("X-Authorization") if not incoming_proxy_key or incoming_proxy_key != PROXY_AUTH_KEY: return jsonify({"error": {"message": "missing or invalid proxy auth key"}}), 401 # --- Construct upstream URL --- query_string = request.query_string.decode("utf-8") upstream_url = f"{SELFHOSTED_BACKEND_URL}/{path}" if query_string: upstream_url += f"?{query_string}" # --- Build upstream headers --- upstream_headers = { "Accept": request.headers.get("Accept", "*/*"), "Accept-Language": request.headers.get("Accept-Language", "en-US"), "User-Agent": request.headers.get("User-Agent", "Mozilla/5.0"), "X-Plugin-Token": GUEST_TOKEN, } if content_type := request.headers.get("Content-Type"): upstream_headers["Content-Type"] = content_type if plugin_origin := request.headers.get("X-Plugin-Origin"): upstream_headers["X-Plugin-Origin"] = plugin_origin if proxy_auth_url := request.headers.get("X-Proxy-Auth-Url"): upstream_headers["X-Proxy-Auth-Url"] = proxy_auth_url if proxy_auth_key := request.headers.get("X-Proxy-Auth-Key"): upstream_headers["X-Proxy-Auth-Key"] = proxy_auth_key if x_authorization := request.headers.get("X-Authorization"): upstream_headers["X-Authorization"] = x_authorization if origin := request.headers.get("Origin"): upstream_headers["Origin"] = origin # --- Get request body --- body = request.get_data() if method not in ["GET", "HEAD"] else None # --- Forward request to backend --- try: upstream_response = requests.request( method=method, url=upstream_url, headers=upstream_headers, data=body, ) except requests.RequestException as e: return jsonify({"error": {"message": "upstream fetch failed"}, "detail": str(e)}), 502 # --- Forward upstream headers as-is --- out_headers = dict(upstream_response.headers) # Remove hop-by-hop headers for header in ["Transfer-Encoding", "Connection", "Keep-Alive"]: out_headers.pop(header, None) # --- Handle binary vs text responses --- # upstream_response.content is already bytes, works for both binary and text return Response( response=upstream_response.content, status=upstream_response.status_code, headers=out_headers, mimetype=upstream_response.headers.get("Content-Type"), ) except Exception as e: return jsonify({"error": {"message": "internal server error"}, "detail": str(e)}), 500 if __name__ == "__main__": app.run(host="0.0.0.0", port=3000) ``` ```java theme={"dark"} import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestClientException; import jakarta.servlet.http.HttpServletRequest; import java.io.IOException; import java.util.Map; import java.util.stream.Collectors; @RestController @RequestMapping("/proxy-auth") public class DatabrainProxyController { @Value("${PROXY_AUTH_KEY}") private String proxyAuthKey; @Value("${SELFHOSTED_BACKEND_URL}") private String selfhostedBackendUrl; @Value("${GUEST_TOKEN}") private String guestToken; private final RestTemplate restTemplate = new RestTemplate(); @RequestMapping(value = "/**", method = { RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH, RequestMethod.DELETE, RequestMethod.OPTIONS }) public ResponseEntity proxyHandler( HttpServletRequest request, @RequestBody(required = false) byte[] body, @RequestHeader Map headers ) { try { String method = request.getMethod(); // --- Handle preflight OPTIONS request --- if ("OPTIONS".equals(method)) { return ResponseEntity.status(204).build(); } // --- Validate proxy key --- String incomingProxyKey = headers.getOrDefault("x-proxy-auth-key", headers.get("x-authorization")); if (incomingProxyKey == null || !incomingProxyKey.equals(proxyAuthKey)) { return ResponseEntity.status(401).body(Map.of( "error", Map.of("message", "missing or invalid proxy auth key") )); } // --- Construct upstream URL --- String path = request.getRequestURI().replaceFirst("^/proxy-auth", ""); String queryString = request.getQueryString(); String upstreamUrl = selfhostedBackendUrl + path; if (queryString != null && !queryString.isEmpty()) { upstreamUrl += "?" + queryString; } // --- Build upstream headers --- HttpHeaders upstreamHeaders = new HttpHeaders(); upstreamHeaders.set("Accept", headers.getOrDefault("accept", "*/*")); upstreamHeaders.set("Accept-Language", headers.getOrDefault("accept-language", "en-US")); upstreamHeaders.set("User-Agent", headers.getOrDefault("user-agent", "Mozilla/5.0")); upstreamHeaders.set("X-Plugin-Token", guestToken); if (headers.containsKey("content-type")) { upstreamHeaders.set("Content-Type", headers.get("content-type")); } if (headers.containsKey("x-plugin-origin")) { upstreamHeaders.set("X-Plugin-Origin", headers.get("x-plugin-origin")); } if (headers.containsKey("x-proxy-auth-url")) { upstreamHeaders.set("X-Proxy-Auth-Url", headers.get("x-proxy-auth-url")); } if (headers.containsKey("x-proxy-auth-key")) { upstreamHeaders.set("X-Proxy-Auth-Key", headers.get("x-proxy-auth-key")); } if (headers.containsKey("x-authorization")) { upstreamHeaders.set("X-Authorization", headers.get("x-authorization")); } if (headers.containsKey("origin")) { upstreamHeaders.set("Origin", headers.get("origin")); } // --- Prepare request entity --- HttpEntity requestEntity = new HttpEntity<>( "GET".equals(method) || "HEAD".equals(method) ? null : body, upstreamHeaders ); // --- Forward request to backend --- ResponseEntity upstreamResponse; try { upstreamResponse = restTemplate.exchange( upstreamUrl, HttpMethod.valueOf(method), requestEntity, byte[].class ); } catch (RestClientException e) { return ResponseEntity.status(502).body(Map.of( "error", Map.of("message", "upstream fetch failed"), "detail", e.getMessage() )); } // --- Forward upstream headers as-is --- HttpHeaders outHeaders = new HttpHeaders(); upstreamResponse.getHeaders().forEach((key, values) -> { // Skip hop-by-hop headers if (!key.equalsIgnoreCase("Transfer-Encoding") && !key.equalsIgnoreCase("Connection") && !key.equalsIgnoreCase("Keep-Alive")) { outHeaders.put(key, values); } }); // --- Handle binary vs text responses --- // byte[] response body works for both binary and text content return ResponseEntity .status(upstreamResponse.getStatusCode()) .headers(outHeaders) .body(upstreamResponse.getBody()); } catch (Exception e) { return ResponseEntity.status(500).body(Map.of( "error", Map.of("message", "internal server error"), "detail", e.getMessage() )); } } } ``` ```go theme={"dark"} package main import ( "io" "log" "net/http" "os" "strings" ) var ( proxyAuthKey = os.Getenv("PROXY_AUTH_KEY") selfhostedBackendURL = os.Getenv("SELFHOSTED_BACKEND_URL") guestToken = os.Getenv("GUEST_TOKEN") ) func proxyHandler(w http.ResponseWriter, r *http.Request) { // --- Handle preflight OPTIONS request --- if r.Method == "OPTIONS" { w.WriteHeader(http.StatusNoContent) return } // --- Validate proxy key --- incomingProxyKey := r.Header.Get("X-Proxy-Auth-Key") if incomingProxyKey == "" { incomingProxyKey = r.Header.Get("X-Authorization") } if incomingProxyKey == "" || incomingProxyKey != proxyAuthKey { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusUnauthorized) w.Write([]byte(`{"error":{"message":"missing or invalid proxy auth key"}}`)) return } // --- Construct upstream URL --- path := strings.TrimPrefix(r.URL.Path, "/proxy-auth") if path == "" { path = "/" } upstreamURL := selfhostedBackendURL + path if r.URL.RawQuery != "" { upstreamURL += "?" + r.URL.RawQuery } // --- Read request body --- var body io.Reader if r.Method != "GET" && r.Method != "HEAD" { body = r.Body defer r.Body.Close() } // --- Create upstream request --- upstreamReq, err := http.NewRequest(r.Method, upstreamURL, body) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(`{"error":{"message":"internal server error"}}`)) return } // --- Build upstream headers --- upstreamReq.Header.Set("Accept", getOrDefault(r.Header.Get("Accept"), "*/*")) upstreamReq.Header.Set("Accept-Language", getOrDefault(r.Header.Get("Accept-Language"), "en-US")) upstreamReq.Header.Set("User-Agent", getOrDefault(r.Header.Get("User-Agent"), "Mozilla/5.0")) upstreamReq.Header.Set("X-Plugin-Token", guestToken) if ct := r.Header.Get("Content-Type"); ct != "" { upstreamReq.Header.Set("Content-Type", ct) } if po := r.Header.Get("X-Plugin-Origin"); po != "" { upstreamReq.Header.Set("X-Plugin-Origin", po) } if pau := r.Header.Get("X-Proxy-Auth-Url"); pau != "" { upstreamReq.Header.Set("X-Proxy-Auth-Url", pau) } if pak := r.Header.Get("X-Proxy-Auth-Key"); pak != "" { upstreamReq.Header.Set("X-Proxy-Auth-Key", pak) } if xa := r.Header.Get("X-Authorization"); xa != "" { upstreamReq.Header.Set("X-Authorization", xa) } if origin := r.Header.Get("Origin"); origin != "" { upstreamReq.Header.Set("Origin", origin) } // --- Forward request to backend --- client := &http.Client{} upstreamResp, err := client.Do(upstreamReq) if err != nil { w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusBadGateway) w.Write([]byte(`{"error":{"message":"upstream fetch failed"},"detail":"` + err.Error() + `"}`)) return } defer upstreamResp.Body.Close() // --- Forward upstream headers as-is --- for key, values := range upstreamResp.Header { // Skip hop-by-hop headers lowerKey := strings.ToLower(key) if lowerKey == "transfer-encoding" || lowerKey == "connection" || lowerKey == "keep-alive" { continue } for _, value := range values { w.Header().Add(key, value) } } // --- Forward upstream response (handles both binary and text) --- w.WriteHeader(upstreamResp.StatusCode) io.Copy(w, upstreamResp.Body) } func getOrDefault(value, defaultValue string) string { if value == "" { return defaultValue } return value } func main() { http.HandleFunc("/proxy-auth/", proxyHandler) log.Println("Proxy server running on port 3000") log.Fatal(http.ListenAndServe(":3000", nil)) } ``` ## Frontend Configuration Configure your frontend to send requests through your proxy server instead of directly to the Databrain backend. ### Configuration Setup ```javascript React theme={"dark"} import { Databrain } from '@databrainhq/plugin'; // Configure proxy authentication globally if (typeof window !== 'undefined') { window.dbn = { proxyAuthUrl: 'https://your-proxy-server.com/proxy-auth', proxyAuthKey: 'your-proxy-authentication-key', isEnableProxyAuth: true }; } function MyDashboard() { return ( ); } ``` ```javascript Vue.js theme={"dark"} ``` ```html Vanilla JavaScript theme={"dark"}
```
**TypeScript Users:** You need to declare the global `window.dbn` type in your project: ```typescript theme={"dark"} declare global { interface Window { dbn?: { proxyAuthUrl?: string; proxyAuthKey?: string; isEnableProxyAuth?: boolean; }; } } ``` ### Configuration Properties | Property | Type | Required | Description | | ------------------------------ | --------- | -------: | ---------------------------------------------------------------------------------------------------------------------------------------- | | `window.dbn.proxyAuthUrl` | `string` | Yes | The full URL of your proxy endpoint. This is sent as the `X-Proxy-Auth-Url` header. Example: `https://your-proxy-server.com/proxy-auth`. | | `window.dbn.proxyAuthKey` | `string` | Yes | Secret key your frontend sends as `X-Proxy-Auth-Key` (or `X-Authorization`) for your proxy to validate. | | `window.dbn.isEnableProxyAuth` | `boolean` | Yes | Enables proxy authentication mode. Use `true` to enable proxy auth. Use `false` (or omit) to use direct token authentication. | Generate a strong, random key and store it securely. This key must match the one your proxy expects. ## Environment Variables Your proxy server requires these environment variables: | Variable | Description | | ------------------------ | --------------------------------------------------------------------------------------------- | | `PROXY_AUTH_KEY` | Secret key to validate incoming requests (must match frontend `proxyAuthKey`) | | `SELFHOSTED_BACKEND_URL` | Your Databrain backend URL (e.g., `https://api.usedatabrain.com`) | | `GUEST_TOKEN` | Your plugin token (saved or [generated via API](/developer-docs/helpers/api-reference/token)) | ## Security Best Practices * **Use Strong Keys:** Generate a cryptographically random proxy authentication key * **Validate Every Request:** Always verify the `X-Proxy-Auth-Key` header * **HTTPS Only:** Ensure your proxy endpoint is only accessible via HTTPS * **Rotate Keys:** Periodically rotate your proxy authentication keys Add rate limiting to prevent abuse: * Limit requests per IP address * Limit requests per user/session * Implement exponential backoff for repeated failures * Log all proxy requests for audit purposes * Monitor for unusual traffic patterns * Set up alerts for authentication failures * Store `GUEST_TOKEN` securely in environment variables * Never expose tokens in client-side code * Consider generating tokens dynamically for enhanced security ## Error Handling ### Common Errors **Error:** `{"error": {"message": "missing or invalid X-Proxy-Auth-Key"}}` **Cause:** The `X-Proxy-Auth-Key` header is missing or doesn't match. **Solution:** Verify that `window.dbn.proxyAuthKey` matches your proxy's `PROXY_AUTH_KEY` environment variable. **Error:** `{"error": {"message": "upstream fetch failed"}}` **Cause:** Your proxy cannot reach the Databrain backend. **Solution:** * Verify `SELFHOSTED_BACKEND_URL` is correct * Check network connectivity from your proxy server * Verify firewall rules allow outbound connections **Error:** `{"error": {"message": "internal server error"}}` **Cause:** An unexpected error occurred in your proxy. **Solution:** Check your proxy server logs for detailed error information. ## Testing Your Proxy Use curl to test your proxy endpoint: ```bash theme={"dark"} # Test with valid proxy key (X-Proxy-Auth-Key) curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \ -H "X-Proxy-Auth-Key: your-proxy-key" # Test with valid proxy key (X-Authorization) curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \ -H "X-Authorization: your-proxy-key" # Test authentication validation (should return 401) curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \ -H "X-Proxy-Auth-Key: invalid-key" # Test authentication validation (should return 401) curl -X GET "https://your-proxy-server.com/proxy-auth/api/health" \ -H "X-Authorization: invalid-key" ``` ## Related Resources Learn about generating guest tokens for your proxy Explore all DataBrain component configuration options Comprehensive guide to DataBrain authentication Learn about multi-tenant access control and security # Publish/Unpublish Metric Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/publish-metric PUT https://api.usedatabrain.com/api/v2/data-app/metrics/publish Publish or unpublish metrics in an embed configuration to control which metrics are visible to end users. Control the visibility of metrics within an embed by publishing or unpublishing them. Published metrics are visible to end users, while unpublished metrics remain hidden but can be published later. This endpoint allows you to dynamically control metric visibility without deleting metrics or modifying embed configurations. Useful for staged rollouts, A/B testing, or hiding metrics temporarily. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The embed configuration ID where the metric is located. * Use the [List Embeds API](/developer-docs/helpers/api-reference/list-embed) to get all embed IDs * Check the response when creating an embed * Available in your data app embed configurations The ID of the metric to publish or unpublish. * Use the [Fetch Metrics by Embed API](/developer-docs/helpers/api-reference/fetch-metrics-by-embed-and-client) to get metric IDs * Available in metric URLs in your dashboard * Returned when creating metrics via API Set the publication status of the metric. * `true`: Publish the metric (make it visible to end users) * `false`: Unpublish the metric (hide it from end users) - **Published metrics**: Visible in the embed, can be accessed by end users - **Unpublished metrics**: Hidden from the embed, but not deleted - **State preservation**: Metric configuration remains intact when unpublished - **Quick toggle**: Can be republished instantly without recreating ## Response The metric ID that was successfully updated on success. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Publish Metric theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/metrics/publish \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_abc123", "metricId": "metric_xyz789", "isPublished": true }' ``` ```bash cURL - Unpublish Metric theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/metrics/publish \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_abc123", "metricId": "metric_xyz789", "isPublished": false }' ``` ```javascript Node.js - Publish Metric icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/metrics/publish', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId: 'embed_abc123', metricId: 'metric_xyz789', isPublished: true }) }); const result = await response.json(); console.log('Metric published:', result.id); ``` ```javascript Node.js - Batch Publish icon="fa-brands fa-node-js" theme={"dark"} // Publish multiple metrics sequentially async function publishMetrics(embedId, metricIds, isPublished = true) { const results = []; for (const metricId of metricIds) { const response = await fetch( 'https://api.usedatabrain.com/api/v2/data-app/metrics/publish', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId, metricId, isPublished }) } ); const result = await response.json(); results.push({ metricId, success: !result.error }); } return results; } // Usage const metrics = ['metric_1', 'metric_2', 'metric_3']; const results = await publishMetrics('embed_abc123', metrics, true); console.log('Published metrics:', results); ``` ```python Python - Publish Metric icon="fa-brands fa-python" theme={"dark"} import requests response = requests.put( 'https://api.usedatabrain.com/api/v2/data-app/metrics/publish', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'embedId': 'embed_abc123', 'metricId': 'metric_xyz789', 'isPublished': True } ) result = response.json() if result.get('error'): print(f"Publish failed: {result['error']['message']}") else: print(f"Metric published: {result['id']}") ``` ```python Python - Batch Operations icon="fa-brands fa-python" theme={"dark"} import requests def publish_metrics(embed_id, metric_ids, is_published=True): """Publish or unpublish multiple metrics""" results = [] for metric_id in metric_ids: response = requests.put( 'https://api.usedatabrain.com/api/v2/data-app/metrics/publish', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'embedId': embed_id, 'metricId': metric_id, 'isPublished': is_published } ) result = response.json() results.append({ 'metricId': metric_id, 'success': 'error' not in result }) return results # Usage metrics = ['metric_1', 'metric_2', 'metric_3'] results = publish_metrics('embed_abc123', metrics, True) print(f"Published {sum(r['success'] for r in results)} metrics") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/metrics/publish') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Put.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { embedId: 'embed_abc123', metricId: 'metric_xyz789', isPublished: true }.to_json response = http.request(request) result = JSON.parse(response.body) if result['error'] puts "Publish failed: #{result['error']['message']}" else puts "Metric published: #{result['id']}" end ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class PublishMetric { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "embedId": "embed_abc123", "metricId": "metric_xyz789", "isPublished": true } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/metrics/publish")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type PublishMetricRequest struct { EmbedId string `json:"embedId"` MetricId string `json:"metricId"` IsPublished bool `json:"isPublished"` } func main() { reqData := PublishMetricRequest{ EmbedId: "embed_abc123", MetricId: "metric_xyz789", IsPublished: true, } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("PUT", "https://api.usedatabrain.com/api/v2/data-app/metrics/publish", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Metric published successfully") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'embed_abc123', 'metricId' => 'metric_xyz789', 'isPublished' => true ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'PUT', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); if (isset($result['error'])) { echo "Publish failed: " . $result['error']['message']; } else { echo "Metric published: " . $result['id']; } ?> ``` ```json 200 - Success theme={"dark"} { "id": "metric_xyz789" } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"embedId\" is required" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Invalid Metric or Embed theme={"dark"} { "error": { "code": "INVALID_METRIC_ID", "message": "Invalid metric id or embed id" } } ``` ```json 500 - Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal Server Error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------- | | `200` | **OK** - Metric publication status updated | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error or invalid IDs | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ----------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid parameters | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INVALID_METRIC_ID` | 500 | Invalid metric or embed ID | | `INTERNAL_SERVER_ERROR` | 500 | Server error | # Rename an Embed Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/rename-embed PUT https://api.usedatabrain.com/api/v2/data-app/embeds/rename Rename an existing embed and optionally its underlying dashboard, without changing its access settings. Use this endpoint to **rename an existing embed**. This is useful when you want to improve naming, align with client labels, or clean up your embed catalog without changing permissions or the underlying data.\ Optionally, you can also rename the underlying dashboard by setting `isRenameDashboard` to `true`. ## Endpoint ```bash theme={"dark"} PUT https://api.usedatabrain.com/api/v2/data-app/embeds/rename ``` ## Authentication All API requests must include your **data app API key** in the `Authorization` header. Get your API token when creating a data app – see the [data app creation guide](/guides/datasources/create-a-data-app) for details. For details on managing API tokens, see the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your data app API key. ```bash theme={"dark"} Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ```bash theme={"dark"} Content-Type: application/json ``` ## Request Body The public embed ID you want to rename (for example: `"embed-123"`).\ You can retrieve embed IDs from the [List All Embeds](/developer-docs/helpers/api-reference/list-embed) API or from the embed configuration UI. The new human‑readable name for the embed configuration.\ Must be a non‑empty string. Optional flag to also rename the underlying dashboard associated with this embed.\ When set to `true`, DataBrain attempts to update the dashboard's name to match the new embed name. Defaults to `false` if omitted. ### Example Request ```bash cURL theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/embeds/rename \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed-123", "name": "Executive Sales Overview", "isRenameDashboard": true }' ``` ```javascript Node.js theme={"dark"} const response = await fetch( 'https://api.usedatabrain.com/api/v2/data-app/embeds/rename', { method: 'PUT', headers: { Authorization: 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify({ embedId: 'embed-123', name: 'Executive Sales Overview', isRenameDashboard: true, }), } ); const data = await response.json(); console.log('Renamed embed:', data.id, '->', data.name); ``` ```python Python theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/embeds/rename" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json", } payload = { "embedId": "embed-123", "name": "Executive Sales Overview", } response = requests.put(url, headers=headers, json=payload) data = response.json() print(f"Renamed embed: {data['id']} -> {data['name']}") ``` ## Response The embed ID that was renamed. The updated name of the embed configuration. Error object if the request failed, otherwise `null` for successful requests. ### Example Responses ```json 200 - Success theme={"dark"} { "id": "embed-123", "name": "Executive Sales Overview", "error": null } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "embedId is required" } } ``` ```json 400 - Invalid Name theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "name cannot be empty" } } ``` ```json 400 - Invalid Embed ID theme={"dark"} { "error": { "code": "INVALID_EMBED_ID", "message": "Embed configuration not found" } } ``` ```json 400 - Invalid API Key theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "Missing or invalid data app" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | -------------------------------------------------------------------- | | `200` | **OK** – Embed renamed successfully | | `400` | **Bad Request** – Invalid body, invalid embed ID, or invalid API key | | `500` | **Internal Server Error** – Unexpected server error | ## Common Error Codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid `embedId` or `name` | | `INVALID_EMBED_ID` | 400 | Embed configuration does not exist | | `INVALID_DATA_APP_API_KEY` | 400 | Missing or invalid data app API key | | `INTERNAL_SERVER_ERROR` | 500 | Unexpected failure on the server | ## Usage Patterns ### Rename for Better UX Labels ```javascript theme={"dark"} // Align embed name with customer-facing label await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds/rename', { method: 'PUT', headers: { Authorization: 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify({ embedId: 'embed-123', name: 'Revenue Overview (ACME)', }), }); ``` ### Bulk Rename Embeds During Migration ```javascript theme={"dark"} const renames = [ { embedId: 'embed-001', name: 'Sales Overview' }, { embedId: 'embed-002', name: 'Marketing Performance' }, ]; for (const rename of renames) { await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds/rename', { method: 'PUT', headers: { Authorization: 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify(rename), }); } ``` ## Related APIs * [Embed a Pre-built Dashboard/Metric](/developer-docs/helpers/api-reference/create-embed) * [Create an Empty Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed) * [Update an Embed](/developer-docs/helpers/api-reference/update-embed) * [Delete an Embed](/developer-docs/helpers/api-reference/delete-embed) * [List All Embeds](/developer-docs/helpers/api-reference/list-embed) # Reset Admin Password (Self-Hosted) Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/reset-admin-password POST https://api.usedatabrain.com/api/v2/service-token/reset-password Change the password for the currently authenticated admin user on a self-hosted Databrain instance. Self-hosted only. Change the password for the admin user identified by the current authentication token. Requires the current password and the new password. The new password should meet the same complexity rules as sign-up (see [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account)). **Self-Hosted Only:** This endpoint is available only on **self-hosted** Databrain instances. **Authentication Requirement:** This endpoint requires an authenticated admin user. Use the Bearer token from [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt). ## Authentication Use a valid admin JWT in the `Authorization` header. Obtain one via [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt). ## Headers Bearer token for the admin whose password is being changed. ``` Authorization: Bearer ``` Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body The admin's current password. The new password. Should meet the same requirements as sign-up: minimum 8 characters, at least one uppercase, one lowercase, one digit, one special character, no spaces. ## Response On success, the API returns **200** with a JSON object: Wrapper object for the response payload. `true` when the password was changed successfully. On error, the API returns a JSON object with `error.code` and `error.message` and an appropriate HTTP status (400 or 500). ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/service-token/reset-password \ --header 'Authorization: Bearer YOUR_ADMIN_ACCESS_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"currentPassword":"OldP@ss1","password":"NewSecureP@ss2"}' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/service-token/reset-password', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_ADMIN_ACCESS_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ currentPassword: 'OldP@ss1', password: 'NewSecureP@ss2' }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); console.log('Password reset:', data.data.success); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/service-token/reset-password" headers = { "Authorization": "Bearer YOUR_ADMIN_ACCESS_TOKEN", "Content-Type": "application/json" } payload = { "currentPassword": "OldP@ss1", "password": "NewSecureP@ss2" } response = requests.post(url, headers=headers, json=payload) data = response.json() if data.get("error"): raise Exception(data["error"].get("message", "Request failed")) print("Password reset:", data["data"]["success"]) ``` ```json Success (200) theme={"dark"} { "data": { "success": true } } ``` ```json Error (400) theme={"dark"} { "error": { "code": "RESET_PASSWORD_ERROR", "message": "The current password is not correct!" } } ``` ```json Error (500) theme={"dark"} { "error": { "code": "SELFHOSTED_APP_ERROR", "message": "This feature is only available for self-hosted instances" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ---------------------------------------------------------------------------- | | `200` | **OK** – Password changed successfully; `data.success` is `true` | | `400` | **Bad Request** – Wrong current password or validation error on new password | | `500` | **Internal Server Error** – Server error or self-hosted-only error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | -------------------------------------------------------------------------------- | ----------- | | `RESET_PASSWORD_ERROR` | Error message from password change (e.g. "The current password is not correct!") | 400 | | `SELFHOSTED_APP_ERROR` | This feature is only available for self-hosted instances | 500 | | `INTERNAL_SERVER_ERROR` | Internal server error or GraphQL error message | 500 | ## Related * [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) – Sign in to get an access token * [Create Admin Account](/developer-docs/helpers/api-reference/create-admin-account) – Create the first admin account # Rotate API Key Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/rotate-api-key POST https://api.usedatabrain.com/api/v2/data-app/rotate-api Rotate your Data App API key to enhance security and manage key lifecycle effectively. Rotate your data app API key to maintain security best practices by periodically refreshing credentials. This endpoint expires the current API key and generates a new one, ensuring seamless transition while maintaining security. The API key used in the `Authorization` header **is** the key being rotated. You only need to provide `expireAt` in the request body — no `key` field required. ## Authentication This endpoint requires the **data app API key** you want to rotate in the `Authorization` header. The key used for authentication is the key that will be expired and replaced with a new one. To access your data app API key: 1. Go to your Databrain dashboard and open the **Data Apps** section. 2. Select the data app whose API key you want to rotate. 3. Find the **API Key** under the data app settings. Use this key as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use the **data app API key** you want to rotate. ``` Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000 ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Duration in seconds until the current API key expires. This allows for a grace period to update your applications before the old key stops working. Accepts a number or a numeric string. * `0` - Expire immediately (instant rotation) * `300` - 5 minutes * `3600` - 1 hour * `86400` - 24 hours * `604800` - 7 days **Recommended:** Set a grace period (e.g., `3600`) to allow time for updating your applications without service interruption. ## Response The newly generated API key (UUID format). Use this key for all future API requests. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Immediate Rotation theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/rotate-api \ --header 'Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000' \ --header 'Content-Type: application/json' \ --data '{ "expireAt": 0 }' ``` ```bash cURL - Rotation with Grace Period theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/data-app/rotate-api \ --header 'Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000' \ --header 'Content-Type: application/json' \ --data '{ "expireAt": 3600 }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/rotate-api', { method: 'POST', headers: { 'Authorization': 'Bearer 550e8400-e29b-41d4-a716-446655440000', 'Content-Type': 'application/json' }, body: JSON.stringify({ expireAt: 3600 }) }); const data = await response.json(); console.log('New API Key:', data.key); ``` ```python Python theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/data-app/rotate-api', headers={ 'Authorization': 'Bearer 550e8400-e29b-41d4-a716-446655440000', 'Content-Type': 'application/json' }, json={ 'expireAt': 3600 } ) data = response.json() print('New API Key:', data['key']) ``` ```java Java theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; HttpClient client = HttpClient.newHttpClient(); ObjectMapper mapper = new ObjectMapper(); Map requestBody = Map.of( "expireAt", 3600 ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/rotate-api")) .header("Authorization", "Bearer 550e8400-e29b-41d4-a716-446655440000") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(requestBody))) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); ``` ```php PHP theme={"dark"} 3600 ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/data-app/rotate-api', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); $result = json_decode($response, true); echo 'New API Key: ' . $result['key']; ?> ``` ```ruby Ruby theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/rotate-api') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer 550e8400-e29b-41d4-a716-446655440000' request['Content-Type'] = 'application/json' request.body = { expireAt: 3600 }.to_json response = http.request(request) result = JSON.parse(response.body) puts "New API Key: #{result['key']}" ``` ```go Go theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type RotateKeyRequest struct { ExpireAt int `json:"expireAt"` } type RotateKeyResponse struct { Key string `json:"key"` } func main() { requestBody := RotateKeyRequest{ ExpireAt: 3600, } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/data-app/rotate-api", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer 550e8400-e29b-41d4-a716-446655440000") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result RotateKeyResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("New API Key: %s\n", result.Key) } ``` ```csharp C# theme={"dark"} using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; public class RotateKeyRequest { [JsonProperty("expireAt")] public int ExpireAt { get; set; } } public class RotateKeyResponse { [JsonProperty("key")] public string Key { get; set; } } var client = new HttpClient(); var request = new RotateKeyRequest { ExpireAt = 3600 }; var json = JsonConvert.SerializeObject(request); var content = new StringContent(json, Encoding.UTF8, "application/json"); client.DefaultRequestHeaders.Add("Authorization", "Bearer 550e8400-e29b-41d4-a716-446655440000"); var response = await client.PostAsync("https://api.usedatabrain.com/api/v2/data-app/rotate-api", content); var result = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync()); Console.WriteLine($"New API Key: {result.Key}"); ``` ```json 200 - Success theme={"dark"} { "key": "7c9e6679-7425-40de-944b-e07fc1f90ae7" } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"expireAt\" is required" } } ``` ```json 400 - Invalid API Key Format theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is not provided or Invalid!" } } ``` ```json 401 - API Key Not Found or Expired theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is invalid or expired!" } } ``` ```json 400 - Not a Data App API Key theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ----------------------------------------------------------------- | | `200` | **OK** - Key rotated successfully | | `400` | **Bad Request** - Invalid request parameters or invalid key state | | `401` | **Unauthorized** - API key not found in DB or already expired | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid `expireAt` parameter | | `AUTHENTICATION_ERROR` | 400 / 401 | API key missing or not a valid UUID (400); or not found / already expired in DB (401) | | `INVALID_DATA_APP_API_KEY` | 400 | Token is a service token (no `dataAppId`), key not found, belongs to a different org, or the key already has an expiry date set | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Related Resources Learn about API token management and authentication Create data apps and generate initial API tokens Generate guest tokens using your data app API key List all embed configurations for your data app # Rotate Service Token Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/rotate-service-token POST https://api.usedatabrain.com/api/v2/service-token/rotate Rotate your service token. Expires the current token after an optional grace period and returns a new token. Rotate your organization service token. The current token is set to expire after a grace period (in seconds), and a new service token is returned. Use this for key rotation and security best practices. The service token used in the `Authorization` header **is** the token being rotated. You only need to provide `expireAt` in the request body — no `token` field required. ## Authentication Use your current **service token** in the `Authorization` header. The token provided here is the one that will be expired and replaced. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. ## Headers Bearer token for API authentication. Use the **service token** you want to rotate. ``` Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000 ``` Must be `application/json` when sending a JSON body. ``` Content-Type: application/json ``` ## Request Body Duration in **seconds** until the current token expires. The old token remains valid until this many seconds from the request, then it is invalidated. Accepts a number or a numeric string. Use `0` to expire immediately. Common values: `0` (immediate), `3600` (1 hour), `86400` (24 hours). ## Response On success, the API returns **200** with a JSON object: The new service token (UUID). Use this for all future service-level API calls. Store it securely; the previous token will expire per `expireAt`. On error, the API returns a JSON object with `error.code` and `error.message` and an appropriate HTTP status (400, 401, or 500). ## Examples ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/service-token/rotate \ --header 'Authorization: Bearer 550e8400-e29b-41d4-a716-446655440000' \ --header 'Content-Type: application/json' \ --data '{"expireAt":3600}' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/service-token/rotate', { method: 'POST', headers: { 'Authorization': 'Bearer 550e8400-e29b-41d4-a716-446655440000', 'Content-Type': 'application/json' }, body: JSON.stringify({ expireAt: 3600 }) }); const data = await response.json(); if (data.error) throw new Error(data.error.message); console.log('New service token:', data.key); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/service-token/rotate" headers = { "Authorization": "Bearer 550e8400-e29b-41d4-a716-446655440000", "Content-Type": "application/json" } payload = { "expireAt": 3600 } response = requests.post(url, headers=headers, json=payload) data = response.json() if data.get("error"): raise Exception(data["error"].get("message", "Request failed")) print("New service token:", data["key"]) ``` ```json Success (200) theme={"dark"} { "key": "7c9e6679-7425-40de-944b-e07fc1f90ae7" } ``` ```json Error (400) - Invalid request body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"expireAt\" is required" } } ``` ```json Error (400) - Invalid API key format theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is not provided or Invalid!" } } ``` ```json Error (401) - API key not found or expired theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "API Key is invalid or expired!" } } ``` ```json Error (400) - Not a service token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json Error (400) - Token already expired theme={"dark"} { "error": { "code": "EXPIRED_SERVICE_TOKEN", "message": "Service token is already expired" } } ``` ```json Error (500) theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal server error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------------------------------------------------- | | `200` | **OK** – New service token returned in `key` | | `400` | **Bad Request** – Missing parameters, invalid key format, not a service token, or token already expired | | `401` | **Unauthorized** – Service token not found in DB or already expired | | `500` | **Internal Server Error** – Server error | ## Possible Errors | Code | Message | HTTP Status | | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | | `INVALID_REQUEST_BODY` | Joi validation message (e.g. `"expireAt" is required`) | 400 | | `AUTHENTICATION_ERROR` | `"API Key is not provided or Invalid!"` – missing/invalid UUID format (400); `"API Key is invalid or expired!"` – not found or expired in DB (401); `"Invalid Service Token"` – token is a data app key, not a service token (400) | 400 / 401 | | `EXPIRED_SERVICE_TOKEN` | Service token is already expired | 400 | | `INVALID_SERVICE_TOKEN` | Invalid service token | 400 | | `INTERNAL_SERVER_ERROR` | Internal server error or GraphQL error message | 500 | ## Related * [Create Service Token](/developer-docs/helpers/api-reference/create-service-token) – Create or save a service token * [Rotate API Key](/developer-docs/helpers/api-reference/rotate-api-key) – Rotate a data app API key * [Create Admin JWT](/developer-docs/helpers/api-reference/create-admin-jwt) – Get admin access token # Semantic Layer API Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/semantic-layer-api APIs to create, read, update, and delete semantic layer configurations for your datamarts. The semantic layer enriches your datamart with business-friendly metadata — descriptions, synonyms, column types, and feedback — to power AI chat mode and improve data discoverability. The Semantic Layer API operates on **existing datamarts**. You must create a datamart first using the [Datamart API](/developer-docs/helpers/api-reference/create-datamart) before adding a semantic layer. ## API Endpoints ### Cloud Databrain Endpoint ```bash theme={"dark"} https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer ``` ### Self-hosted Databrain Endpoint ```bash theme={"dark"} /api/v2/data-app/datamarts/semantic-layer ``` The same routes are also mounted at `/api/v2/dataApp/...` (camelCase) if your client or proxy uses that prefix. ## Authentication All semantic layer endpoints require a **service token** (not a data app API token). Data app tokens will be rejected with a `403 AUTHENTICATION_ERROR`. Bearer token for API authentication. Must be a service token. ``` Authorization: Bearer dbn_live_abc123... ``` ## Available Operations Retrieve the semantic layer for a datamart including tables, columns, and completion score. Add semantic metadata to a datamart that doesn't have one yet. Modify existing semantic layer metadata (descriptions, synonyms, feedback). Remove all semantic layer metadata from a datamart. ## Key Concepts ### Tables & Columns Enrich your datamart tables and columns with: * **Descriptions** — natural-language explanations of what the data represents * **Synonyms** — alternative names users might search for (up to 10 per entity) * **Column types** — semantic classifications like `String`, `Number`, `ENUM`, `Range`, `Identifier`, etc. * **Column type config** — type-specific shape (e.g. value-to-description maps for `ENUM` / `String` types, `{ lowerLimit, upperLimit }` for `Range`, strings for `Expression` / `JSON`) * **Miscellaneous info** — extra context for the AI to improve query generation ### Feedback A free-text field (up to 2000 characters) providing global context about the datamart to guide AI behavior. ### Completion Score A computed score (0–100) reflecting how thoroughly the semantic layer is filled out. Returned by the GET endpoint. # SMTP Settings Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/smtp-settings PUT https://api.usedatabrain.com/api/v2/data-app/smtp-settings Configure SMTP settings for your data app so scheduled reports can be sent by email. Set or update the SMTP configuration used to send scheduled reports and other emails for your data app. The API validates the connection before saving; if the credentials or server are invalid, the request fails and settings are not stored. You can also configure email in the UI: **Settings → Embed Settings → Email Settings**. This API is for automation and integration. See [Email Settings for Scheduled Reports](/guides/preview-of-dashboards/email-settings-for-scheduled-reports) for the UI flow. ## Endpoint ``` PUT https://api.usedatabrain.com/api/v2/data-app/smtp-settings ``` ## Authentication All requests must include your **data app API key** in the `Authorization` header. See the [data app creation guide](/guides/datasources/create-a-data-app) and the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your data app API key. ``` Authorization: Bearer dbn_live_abc123... ``` Must be `application/json`. ## Request Body SMTP server hostname (e.g. `smtp.example.com`). SMTP server port as integer (e.g. `587` for STARTTLS, `465` for implicit SSL). SMTP authentication username. SMTP authentication password. Sender email address. Must be a valid email format (e.g. `noreply@example.com`). Reply-to email address. Must be a valid email format. Whether to use TLS/SSL for the connection. Use `true` for port 465; use `false` for port 587 with STARTTLS. ## Response `true` when settings were saved successfully. ## Examples ```bash cURL theme={"dark"} curl --request PUT \ --url 'https://api.usedatabrain.com/api/v2/data-app/smtp-settings' \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "host": "smtp.example.com", "port": 587, "username": "smtp-user", "password": "your-password", "fromAddress": "noreply@example.com", "replyToAddress": "support@example.com", "secure": false }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/smtp-settings', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify({ host: 'smtp.example.com', port: 587, username: 'smtp-user', password: 'your-password', fromAddress: 'noreply@example.com', replyToAddress: 'support@example.com', secure: false, }), }); const result = await response.json(); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app/smtp-settings" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json", } payload = { "host": "smtp.example.com", "port": 587, "username": "smtp-user", "password": "your-password", "fromAddress": "noreply@example.com", "replyToAddress": "support@example.com", "secure": False, } response = requests.put(url, headers=headers, json=payload) data = response.json() ``` ```json Success theme={"dark"} { "data": { "success": true } } ``` ```json Error – Validation theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"fromAddress\" must be a valid email" } } ``` ```json Error – SMTP test failed theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "SMTP connection test failed" } } ``` ```json Error – Invalid API key theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ## Error codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------------------------------------ | | `INVALID_DATA_APP_API_KEY` | 400 | Missing or invalid data app API key | | `INVALID_SERVICE_TOKEN` | 400 | Invalid or expired token; cannot resolve company context | | `INVALID_REQUEST_BODY` | 400 | Invalid or missing body fields (e.g. invalid email, missing host) | | `INTERNAL_SERVER_ERROR` | 400 / 500 | SMTP connection test failed (400) or unexpected server error (500) | ## Related Configure email in the UI Manage embedding domains # Sync Datasource Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/sync-datasource POST https://api.usedatabrain.com/api/v2/datasource/sync ### Overview The Databrain APIs provides endpoints to sync you Datasource in both Cloud Databrain and Selfhosted Databrain environment. To use the API, you need to pass a parameter `datasourceId`. ## Self-hosted Databrain Endpoint ```bash theme={"dark"} POST /api/v2/datasource/sync ``` ## Headers Bearer [API TOKEN](https://docs.usedatabrain.com/developer-docs/helpers/api-token) ## Request Body Input object containing the datasource configuration. The unique identifier of the datasource to sync. You can find this in the URL query params on the datasource page. ## Request Example ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/datasource/sync \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "input": { "datasourceId": "your-datasource-id" } }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/datasource/sync', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ input: { datasourceId: 'your-datasource-id' } }) }); const data = await response.json(); console.log(data.data.message); ``` ```python Python theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/datasource/sync', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'input': { 'datasourceId': 'your-datasource-id' } } ) data = response.json() print(data['data']['message']) ``` ## Response Body ```json theme={"dark"} { "data": { "message": "Sync completed" } } ``` > Get your `datasourceId` from the URL query params on the datasource page. ## Error Codes * **INVALID\_REQUEST\_BODY**: The request body is invalid. * **DATASOURCE\_ID\_ERROR**: The datasource ID provided does not exist or is invalid. # Guest Token Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/token POST https://api.usedatabrain.com/api/v2/guest-token/create Generate secure guest tokens for embedding DataBrain dashboards and metrics in your application. Guest tokens are designed for frontend embedding. Never expose your API key in frontend code - always generate tokens from your backend. **Simple Usage:** Only `clientId` and `dataAppName` are required. All other parameters (`params`, `permissions`, `expiryTime`, `datasourceName`, `datamartName`) are optional for advanced use cases. The request body is validated strictly — any field not documented on this page is rejected with `INVALID_REQUEST_BODY`. In particular, `dataAppId`, `client_id`, `tenant_id`, and `permissions.dashboards` are **not** valid fields. Guest tokens are free. There is no charge, metering, or purchase involved in generating them. **Advanced Features Available:** * Dashboard & metric-level filtering (`dashboardAppFilters`, `appFilters`) * Per-dashboard metric visibility (`params.hideDashboardMetrics`) * Embed allowlisting (`params.allowedEmbeds`) * Fine-grained permissions control (`permissions` object) * Private metrics for end users (`userIdentifier`) * Timezone-aware queries (`params.timezone`) * Multi-datasource support (`datasourceName`) * Multi-datamart support (`datamartName`) * Conditional filter visibility (`hideDashboardFilters`, `isShowOnUrl`) * Token expiration management (`expiryTime`) ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' ``` #### Cloud Databrain Endpoint: ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/guest-token/create ``` #### Self-hosted Databrain Endpoint: ```http theme={"dark"} POST /api/v2/guest-token/create ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Unique identifier for the end user. This should be your user's ID from your system. Used for row-level security and access control. Use `"None"` as the value if no tenancy is configured for your workspace (e.g. `"clientId": "None"`). * Use your internal user ID * Keep it consistent across sessions * Alphanumeric characters recommended The name of your data application. Must match an existing data app in your workspace and be alphanumeric. * `"sales-dashboard"` * `"marketing-metrics"` * `"customer-analytics"` Additional parameters for token customization and filtering. Optional allowlist of IDs this token can load. * Each entry must match the ID you pass to the embed component's `dashboardId` attribute — embed IDs and dashboard IDs both resolve. * If you provide `allowedEmbeds`, loading any ID not in the list fails with `UNAUTHORIZED`. * If this is omitted, there is no restriction on which embeds can be loaded by the token. * This is useful to restrict or enforce which dashboards or embedded analytics a guest can view, adding an extra layer of access control. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "allowedEmbeds": ["", ""] } } ``` Row-level security rules per metric. Each entry is `{ "metricId": string, "values": object }`, where `values` maps RLS variable names to the values enforced for this token. Unlike dashboard filters, RLS values are enforced server-side and cannot be changed by the end user. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "rlsSettings": [ { "metricId": "metric_123", "values": { "customer_id": "456", "region": "north-america" } } ] } } ``` End-user dashboard- and metric-filter controls. Supported fields include the filter permissions, optional column allowlists, and filter-name rename permissions. Application-level filters for controlling access to individual metrics. Unlike RLS settings, app filters restrict access without requiring end user input. App filters are ideal for implementing metric-level access control that is invisible to end users. The metric ID to apply filters to. Required if appFilters is provided. Filter values to apply to the metric. Supports multiple data types: Keys in `values` can use either the filter `label` or internal filter `name` (case-insensitive). * **Boolean**: `"paid_orders": true` * **Number**: `"amount": 500` * **String**: `"country": "USA"` * **Array** (multi-select): `"countries": ["USA", "CANADA"]` * **Date preset shortcut**: `"order_date": "Last 30 days"` * **SQL Query**: `{ "sql": "SELECT...", "columnName": "name" }` ```json theme={"dark"} { "metricId": "metric_123", "values": { "paid_orders": true, "amount": 500, "country": ["USA", "CANADA"], "region": { "sql": "SELECT \"name\" FROM \"public\".\"regions\" WHERE isActive=true", "columnName": "name" } } } ``` Dashboard-level filters that apply to all metrics on a dashboard. Supports multiple filter types for flexible data filtering. The dashboard ID to apply filters to. Required if dashboardAppFilters is provided. Filter values to apply to the dashboard. Supports various filter formats: Keys in `values` can use either the dashboard filter `label` or internal filter `name` (case-insensitive). * **Single string**: `"name": "Eric"` * **Multi-select**: `"country": ["USA", "CANADA"]` * **Date range**: `"timePeriod": { "startDate": "2024-01-01", "endDate": "2024-03-23" }` * **Date preset shortcut**: `"timePeriod": "Last 30 days"` * **Number range**: `"price": { "min": 1000, "max": 5000 }` * **SQL query**: `{ "sql": "SELECT...", "columnName": "name" }` ```json theme={"dark"} { "dashboardId": "dashboard_abc123", "values": { "name": "Eric", "country": ["USA", "CANADA"], "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-03-23" }, "price": { "min": 1000, "max": 5000 }, "region": { "sql": "SELECT \"name\" FROM \"public\".\"countries\" WHERE isEnabled=true", "columnName": "name" } }, "isShowOnUrl": false } ``` Controls visibility of filter values in URL search parameters. When `false`, filters are applied but not visible to end users in the URL. Set to `false` to hide sensitive filter criteria from end users while still applying the filtering logic. Array of filter names to hide from the dashboard interface. Use this to conditionally hide specific filters based on user permissions or context. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "hideDashboardFilters": ["region_filter", "date_range", "status"] } } ``` Metrics to hide from specific embedded dashboards. Each item targets one dashboard and removes the selected metrics and their layout cards from that dashboard's embed response. External ID of the dashboard on which to hide the metrics. The dashboard must belong to the data app and workspace scope associated with the API token. Public metric IDs to hide on the specified dashboard. Every metric must be present on that dashboard. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "hideDashboardMetrics": [ { "dashboardId": "sales-overview", "metricIds": ["revenue-by-region", "gross-margin"] } ] } } ``` This setting controls dashboard presentation for this guest token. It does not delete, archive, or change the metrics globally. Configurations for other dashboard IDs do not affect the current dashboard. If the same dashboard appears more than once, the backend combines the metric IDs from all matching entries. Optional advanced access controls for end-user dashboard filtering. Enables or disables end-user dashboard filter controls in embedded mode. Optional allowlist for dashboard filterable columns. Each item must include `tableName` and `columns`. Fully qualified table name used in dashboard filters. Column names allowed for dashboard filter evaluation for the specified table. Enables or disables end-user metric filter interactions in embedded mode. Optional allowlist for columns that end users can use in metric filters. Each item must include `tableName` and `columns`. Fully qualified table name used in metric filters. Column names allowed for metric filter evaluation for the specified table. Enables or disables end-user renaming of dashboard filter labels in embedded mode. Enables or disables end-user renaming of metric filter labels in embedded mode. Unique identifier for the end user in your system. Enables features like creating **private metrics** and **publishing metrics** directly from the embed view. The `isAllowPrivateMetricsByDefault` setting must be enabled when creating the dashboard for this feature to work. When set, metrics created by this user identifier can be: * Saved as private (visible only to this user) * Published to share with other users * Managed independently per user ```json theme={"dark"} { "clientId": "client-123", "dataAppName": "analytics-app", "params": { "userIdentifier": "user_john_doe_789" } } ``` IANA timezone string for timezone-aware queries and date/time formatting. When provided, SQL queries will be executed with this timezone setting, ensuring consistent date/time handling across different timezones. The timezone is used to set the database session timezone for SQL queries, ensuring that date/time operations are performed in the specified timezone. **Supported Datasources:** * Clickhouse * Trino * Redshift * CockroachDB * Postgres * MSSQL Want to implement timezone-aware dashboards end to end? See the full step-by-step guide: [Timezone Handling in Guest Token](/developer-docs/solutions-alchemy/guest-token-timezone). * `"UTC"` - Coordinated Universal Time * `"America/New_York"` - Eastern Time (US) * `"America/Los_Angeles"` - Pacific Time (US) * `"Europe/London"` - Greenwich Mean Time / British Summer Time * `"Asia/Kolkata"` - Indian Standard Time * `"Australia/Sydney"` - Australian Eastern Time ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "timezone": "America/New_York" } } ``` Permission settings for the embedded interface. Allow archiving metrics. Allow managing metrics (view, edit, organize). Allow creating custom dashboard views. Allow updating metric configurations. Allow customizing dashboard layout. Allow viewing underlying data behind charts. Allow downloading metric data. Show the sidebar navigation. Show the dashboard name in the interface. Disable metric creation in embedded dashboards. When set to `true`, end users cannot create new metrics. * Setting this to `true` disables only the metric creation feature for end users in the embedded interface. * If you want to allow metric creation again, mint a new token with this option set to `false` or removed, and check the Data App's Access Control settings and the component options (`options.disableMetricCreation`). * Overrides other metric creation permissions when enabled. **Optional.** Token expiration time in milliseconds from now. If not provided, token never expires. * `3600000` - 1 hour (3600 \* 1000 ms) * `86400000` - 24 hours * `604800000` - 7 days **Optional.** Scope the token to a specific Datamart. **Optional.** Datasource name for multi-datasource connection setups. Required when your data app uses multiple datasources. The datasource name is available in the **Data Studio** tab of your dashboard. This parameter is only necessary if you have configured multiple datasources for your data app. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "analytics-app", "datasourceName": "production_db_replica" } ``` **Optional.** Datamart name for multi-datamart connection setups. Use this when your data app can resolve multiple datamarts and you want to pin token execution to one datamart. If both `datasourceName` and `datamartName` are omitted, Databrain resolves defaults from the data app context. ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "analytics-app", "datamartName": "sales-datamart" } ``` ```bash cURL (Simple) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "user-456", "dataAppName": "sales-dashboard" }' ``` ```bash cURL (Advanced) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "rlsSettings": [ { "metricId": "metric_123", "values": { "customer_id": "456", "region": "north-america" } } ] }, "expiryTime": 3600000 }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/guest-token/create', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: 'user-456', dataAppName: 'sales-dashboard', params: { rlsSettings: [ { metricId: 'metric_123', values: { customer_id: '456', region: 'north-america' } } ] }, expiryTime: 3600000 }) }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/guest-token/create', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'clientId': 'user-456', 'dataAppName': 'sales-dashboard', 'params': { 'rlsSettings': [ { 'metricId': 'metric_123', 'values': { 'customer_id': '456', 'region': 'north-america' } } ] }, 'expiryTime': 3600000 } ) ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.List; HttpClient client = HttpClient.newHttpClient(); ObjectMapper mapper = new ObjectMapper(); Map requestBody = Map.of( "clientId", "user-456", "dataAppName", "sales-dashboard", "params", Map.of( "rlsSettings", List.of( Map.of( "metricId", "metric_123", "values", Map.of( "customer_id", "456", "region", "north-america" ) ) ) ), "expiryTime", 3600000 ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/guest-token/create")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(requestBody))) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'user-456', 'dataAppName' => 'sales-dashboard', 'params' => [ 'rlsSettings' => [ [ 'metricId' => 'metric_123', 'values' => [ 'customer_id' => '456', 'region' => 'north-america' ] ] ] ], 'expiryTime' => 3600000 ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/guest-token/create', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/guest-token/create') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { clientId: 'user-456', dataAppName: 'sales-dashboard', params: { rlsSettings: [ { metricId: 'metric_123', values: { customer_id: '456', region: 'north-america' } } ] }, expiryTime: 3600000 }.to_json response = http.request(request) ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "net/http" ) type RLSValue struct { CustomerID string `json:"customer_id"` Region string `json:"region"` } type RLSSetting struct { MetricID string `json:"metricId"` Values RLSValue `json:"values"` } type Params struct { RLSSettings []RLSSetting `json:"rlsSettings"` } type RequestBody struct { ClientID string `json:"clientId"` DataAppName string `json:"dataAppName"` Params Params `json:"params"` ExpiryTime int `json:"expiryTime"` } func main() { requestBody := RequestBody{ ClientID: "user-456", DataAppName: "sales-dashboard", Params: Params{ RLSSettings: []RLSSetting{ { MetricID: "metric_123", Values: RLSValue{ CustomerID: "456", Region: "north-america", }, }, }, }, ExpiryTime: 3600000, } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/guest-token/create", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() } ``` ```csharp C# icon="fa-solid fa-code" theme={"dark"} using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; public class GuestTokenRequest { [JsonProperty("clientId")] public string ClientId { get; set; } [JsonProperty("dataAppName")] public string DataAppName { get; set; } [JsonProperty("params")] public Params Params { get; set; } [JsonProperty("expiryTime")] public int ExpiryTime { get; set; } } public class Params { [JsonProperty("rlsSettings")] public RLSSetting[] RlsSettings { get; set; } } public class RLSSetting { [JsonProperty("metricId")] public string MetricId { get; set; } [JsonProperty("values")] public Values Values { get; set; } } public class Values { [JsonProperty("customer_id")] public string CustomerId { get; set; } [JsonProperty("region")] public string Region { get; set; } } var client = new HttpClient(); var request = new GuestTokenRequest { ClientId = "user-456", DataAppName = "sales-dashboard", Params = new Params { RlsSettings = new[] { new RLSSetting { MetricId = "metric_123", Values = new Values { CustomerId = "456", Region = "north-america" } } } }, ExpiryTime = 3600000 }; var json = JsonConvert.SerializeObject(request); var content = new StringContent(json, Encoding.UTF8, "application/json"); client.DefaultRequestHeaders.Add("Authorization", "Bearer dbn_live_abc123..."); var response = await client.PostAsync("https://api.usedatabrain.com/api/v2/guest-token/create", content); ``` ```bash cURL (Dashboard Filters) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "user-789", "dataAppName": "regional-analytics", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard_abc123", "values": { "region": ["north-america", "europe"], "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-12-31" }, "revenue": { "min": 10000, "max": 500000 } }, "isShowOnUrl": false } ] }, "expiryTime": 7200000 }' ``` ```bash cURL (Permissions + Private Metrics) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "tenant-456", "dataAppName": "self-service-analytics", "params": { "userIdentifier": "analyst_john_123", "timezone": "America/New_York", "appFilters": [ { "metricId": "metric_abc", "values": { "paid_orders": true, "amount": 1000, "countries": ["USA", "CANADA"] } } ], "hideDashboardFilters": ["internal_cost", "profit_margin"] }, "permissions": { "isEnableArchiveMetrics": true, "isEnableManageMetrics": true, "isEnableMetricUpdation": true, "isEnableCustomizeLayout": true, "isEnableUnderlyingData": false, "isEnableDownloadMetrics": true, "isDisableMetricCreation": false } }' ``` ```bash cURL (Multi-Datasource) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "production-client", "dataAppName": "enterprise-bi", "datasourceName": "production_replica_west", "params": { "dashboardAppFilters": [ { "dashboardId": "ops_dashboard", "values": { "environment": "production" } } ] }, "expiryTime": 3600000 }' ``` ```json 200 - Success theme={"dark"} { "token": "3affda8b-7bd4-4a88-9687-105a94cfffab" } ``` ```json 400 - Bad Request theme={"dark"} { "error": { "code": "INVALID_DATA_APP_NAME", "message": "invalid data app name, data app name not found", "status": 400 } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_API_KEY", "message": "Invalid or missing API key", "status": 401 } } ``` ## Response UUID token for authentication. Pass this to your frontend component for embedding. Error object if the request failed, otherwise `null` for successful requests. ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Request succeeded | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `403` | **Forbidden** - Access denied to resource | | `404` | **Not Found** - Resource not found | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Server error occurred | ## Error Codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing API key | | `INVALID_REQUEST_BODY` | 400 | Missing, invalid, or unknown parameters (unrecognized fields are rejected) | | `CLIENT_ID_ERROR` | 400 | Invalid clientId format or value | | `INVALID_DATA_APP_NAME` | 400 | `dataAppName` doesn't match any Data App (case-sensitive) | | `WORKSPACE_ID_ERROR` | 404 | Workspace not found or inaccessible | | `DASHBOARD_PARAM_ERROR` | 400 | Invalid dashboard filter parameters or a `hideDashboardMetrics` dashboard outside the API token's data app/workspace scope | | `INVALID_METRIC_ID` | 400 | A `hideDashboardMetrics.metricIds` value is not present on the specified dashboard | | `APP_FILTER_PARAM_ERROR` | 400 | Invalid app filter configuration | | `RLS_SETTINGS_PARAM_ERROR` | 400 | Invalid RLS settings | | `DATASOURCE_NAME_ERROR` | 400 | `datasourceName` doesn't resolve | | `DATAMART_NAME_ERROR` | 400 | `datamartName` doesn't resolve | | `INTERNAL_SERVER_ERROR` | 500 | Server error | These are the mint-time errors from this endpoint. At embed runtime (after minting), the distinct errors are `INVALID_TOKEN` (token not found in this deployment), `TOKEN_EXPIRED`, `UNAUTHORIZED_ORIGIN`, `UNAUTHORIZED`, and `INVALID_ID` — see the [Error Codes Reference](/developer-docs/reference/error-codes). Rate limiting surfaces as HTTP `429` with a `Retry-After` header (see [Rate Limiting](/developer-docs/rate-limiting)). ## Quick Start Guide **Rate Limiting**: API requests are limited to prevent abuse. Implement exponential backoff for rate limited requests (429 status). ## Next Steps Create embed configurations for your data apps Create data apps and get your API tokens Learn how to embed dashboards in your app Learn more about API token management # Update Data App Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-data-app PUT https://api.usedatabrain.com/api/v2/data-app Update the name and settings of an existing Data App. Update the name and configuration of an existing Data App. This is useful for renaming Data Apps or updating their settings. Updating a Data App name will not affect existing embed configurations or API tokens. They will continue to work with the renamed Data App. **Authentication Requirement:** This endpoint requires a **service token** (not a data app API key). Service tokens have elevated permissions to manage Data Apps across your organization. ## Endpoint Formats ``` PUT https://api.usedatabrain.com/api/v2/data-app ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` PUT https://api.usedatabrain.com/api/v2/dataApp ``` This endpoint still works but will be deprecated. Please migrate to the new endpoint format. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token (not data app API key). ``` Authorization: Bearer service_token_xyz... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The current name of the Data App to update. This must exactly match an existing Data App name. * Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to get all Data App names * Check your Databrain dashboard for Data App configurations * The name is case-sensitive The new name for the Data App. This name must be unique within your organization. * Names must be unique within your organization * Use descriptive names that indicate the purpose (e.g., "Customer Portal Analytics", "Partner Dashboard") * Avoid special characters that might cause URL encoding issues ## Response The updated name of the Data App. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Customer Analytics", "updateName": "Updated Customer Analytics" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app', { method: 'PUT', headers: { 'Authorization': 'Bearer service_token_xyz...', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Customer Analytics', updateName: 'Updated Customer Analytics' }) }); const data = await response.json(); console.log('Updated Data App:', data.name); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests url = "https://api.usedatabrain.com/api/v2/data-app" headers = { "Authorization": "Bearer service_token_xyz...", "Content-Type": "application/json" } payload = { "name": "Customer Analytics", "updateName": "Updated Customer Analytics" } response = requests.put(url, headers=headers, json=payload) data = response.json() print(f"Updated Data App: {data['name']}") ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class UpdateDataApp { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "name": "Customer Analytics", "updateName": "Updated Customer Analytics" }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app")) .header("Authorization", "Bearer service_token_xyz...") .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println("Response: " + response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type UpdateDataAppRequest struct { Name string `json:"name"` UpdateName string `json:"updateName"` } type UpdateDataAppResponse struct { Name string `json:"name"` Error interface{} `json:"error"` } func main() { requestBody := UpdateDataAppRequest{ Name: "Customer Analytics", UpdateName: "Updated Customer Analytics", } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("PUT", "https://api.usedatabrain.com/api/v2/data-app", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer service_token_xyz...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() var result UpdateDataAppResponse json.NewDecoder(resp.Body).Decode(&result) fmt.Printf("Updated Data App: %s\n", result.Name) } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Customer Analytics', 'updateName' => 'Updated Customer Analytics' ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/data-app', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'PUT', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer service_token_xyz...', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); $result = json_decode($response, true); echo 'Updated Data App: ' . $result['name']; ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Put.new(uri) request['Authorization'] = 'Bearer service_token_xyz...' request['Content-Type'] = 'application/json' request.body = { name: 'Customer Analytics', updateName: 'Updated Customer Analytics' }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Updated Data App: #{result['name']}" ``` ```json 200 - Success theme={"dark"} { "name": "Updated Customer Analytics" } ``` ```json 400 - Invalid Request Body theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"updateName\" is required" } } ``` ```json 400 - Data App Not Found theme={"dark"} { "error": { "code": "DATA_APP_NOT_FOUND", "message": "Data app not found" } } ``` ```json 400 - Invalid Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Invalid Service Token" } } ``` ```json 500 - Internal Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "INTERNAL_SERVER_ERROR" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Data App updated successfully | | `400` | **Bad Request** - Invalid request parameters | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | -------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid parameters | | `DATA_APP_NOT_FOUND` | 400 | Data App with specified name not found | | `AUTHENTICATION_ERROR` | 400 | Invalid or missing service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide In **Settings** page, navigate to the **Service Tokens** section. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use the [List Data Apps](/developer-docs/helpers/api-reference/list-data-apps) API to verify the current Data App configuration: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` Make a PUT request with the current name and the new name: ```bash theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app \ --header 'Authorization: Bearer service_token_xyz...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Current Data App Name", "updateName": "New Data App Name" }' ``` List Data Apps again to confirm the update: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app' \ --header 'Authorization: Bearer service_token_xyz...' ``` ## Next Steps View all Data Apps in your organization Create new Data Apps for your organization Remove Data Apps you no longer need Generate API tokens for your Data Apps # Update Datamart Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-datamart PUT https://api.usedatabrain.com/api/v2/data-app/datamarts Update an existing datamart's table configurations and tenancy settings without recreating from scratch. Update the table list and tenancy settings of an existing datamart. This endpoint allows you to modify which tables and columns are accessible through the datamart, as well as update multi-tenant configurations. **Destructive Operation:** Updating a datamart will delete all existing table and column configurations before applying the new ones. Ensure your new configuration includes all tables and columns you need. The datamart name identifies which datamart to update and cannot be changed through this endpoint. To rename a datamart, you'll need to delete the old one and create a new one with the desired name. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the existing datamart to update. Must match exactly (case-sensitive). * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to get all datamart names * Names are case-sensitive and must match exactly * This field identifies which datamart to update (cannot be used to rename) Array of tables with columns to include in the datamart. Optional - if not provided, only tenancy settings will be updated. **Replaces all existing tables:** The new table list completely replaces the existing configuration. Include all tables you want to keep. Table name from your datasource. Must exist in the datasource schema. Optional schema name (required only for schema-based datasources like PostgreSQL, SQL Server). Optional column name in this table that identifies the client/tenant. This column is used for multi-tenant data isolation at the table level. Must exist in the table schema. * Used for table-level tenancy when `tenancyLevel` is `TABLE` * The column should contain client/tenant identifiers Optional flag to hide the table from the datamart interface. Optional label for the table to provide a human-readable display name. When provided, this label can be used in the UI instead of the technical table name for better readability. * Provides a user-friendly display name for the table * Useful when table names are cryptic or technical * Does not affect the actual table reference in queries Optional wildcard index pattern for OpenSearch tables. When set, this value is used as the table name in queries, enabling you to query multiple OpenSearch indices that match a pattern. * Only applicable to **OpenSearch** datasources * Accepts a valid OpenSearch index wildcard pattern (e.g., `logs-*`, `events-2024-*`) * When set, the wildcard value is used instead of the exact `name` when constructing the FROM clause * Allows a single datamart table to cover multiple time-partitioned or sharded OpenSearch indices List of column objects for this table. Must be non-empty. Column name from the table. Must exist in the datasource schema. Optional alias for the column to display a different name. Optional label for the column for better readability. Optional flag to hide the column from the datamart interface. Defaults to `false`. Optional flag to mark this as a custom/calculated column. When `true`, the `sql` field is required to define the column's SQL expression. * Custom columns allow you to define calculated fields using SQL expressions * The `name` field should reference an existing column from the datasource schema * Use the `alias` field to give the calculated column a custom display name * The SQL expression can reference other columns from the same table * Useful for derived metrics, concatenations, or transformations SQL expression that defines the calculated value for a custom column. **Required when** `isCustomColumn` is `true`. The expression can reference other columns from the same table. * Simple calculation: `quantity * unit_price` * Date extraction: `EXTRACT(YEAR FROM order_date)` * String concatenation: `CONCAT(first_name, ' ', last_name)` * Case statement: `CASE WHEN status = 'active' THEN 1 ELSE 0 END` Optional flag to indicate if this column should be treated as an aggregate column. When `true`, the column is marked as `AGGREGATE` drop type for metric calculations. * Aggregate columns are used for pre-aggregated metrics * Affects how the column behaves in metric calculations and drag-drop operations * Common for SUM, COUNT, AVG type pre-calculated values Optional flag to enable default aggregation for the column. When `true`, Databrain uses the value set in `defaultAggregation` when the column is added as a measure. Optional field to define the default aggregation applied to the column when used as a measure. ```json theme={"dark"} { "allowAggregate": true, "defaultAggregation": "COUNT_DISTINCT" } ``` Optional flag to enable timezone conversion for this column. When `true`, the column's datetime values are converted using the timezone passed as `params.timezone` in the guest token at query execution time. This field has no effect unless `params.timezone` is set in the guest token. See [Timezone Handling in Guest Token](/developer-docs/solutions-alchemy/guest-token-timezone) for the full setup guide. * Apply to datetime or timestamp columns that store values in UTC or a fixed timezone * The timezone is sourced from `params.timezone` in the guest token — not a user or workspace setting * Supported datasources: Postgres, CockroachDB, Trino, Athena, BigQuery, MSSQL, OpenSearch, Databricks, Clickhouse, Redshift, Snowflake * Has no effect on non-datetime column types Optional default sort direction for the column. Supported values are `ASC` and `DESC`. The value is propagated to data-app embed access settings and used as the initial sort direction when this column is selected during metric creation. Pass an empty string (`""`) or `null`, or omit this field on a submitted column, to clear its default sort. Values are case-sensitive; lowercase values such as `"asc"` fail validation. Multi-tenant configuration for the datamart. Optional - if not provided, existing tenancy settings remain unchanged. * **TABLE level**: Uses a dedicated table to map client identifiers * **DATABASE level**: Each client has a separate database * **MULTI\_DATABASE level**: Supports multi-database tenancy with optional primary database routing * All fields are optional; omitted fields retain their existing values The level at which tenant isolation occurs. Must be one of: `TABLE`, `DATABASE`, or `MULTI_DATABASE`. * `TABLE`: Client mapping is stored in a specific table (most common) * `DATABASE`: Each client has a separate database instance * `MULTI_DATABASE`: Tenancy spans multiple databases with optional default routing via `primaryDatabase` **Optional:** If not provided, existing tenancy level is retained. Data type of the client identifier column. Must be either `NUMBER` or `STRING`. **Required when** `tenancySettings.tenancyLevel` is set to `TABLE` in the request. Optional primary database name used for `DATABASE` and `MULTI_DATABASE` tenancy levels. * If `tenancyLevel` is `DATABASE` or `MULTI_DATABASE`, this value is stored (or `null` when omitted). * In update requests, if `tenancySettings` is sent without `tenancyLevel`, backend logic clears `primaryDatabase` to `null`. * If `tenancyLevel` is `TABLE`, backend logic also clears `primaryDatabase` to `null`. To avoid accidental clearing, include `tenancySettings.tenancyLevel` whenever you send `tenancySettings`. Schema name where the client mapping table is located. **Required when** `tenancySettings.tenancyLevel` is set to `TABLE` in the request. Name of the table that contains client mapping information. **Required when** `tenancySettings.tenancyLevel` is set to `TABLE` in the request. Column name in the mapping table that stores the client identifier. **Required when** `tenancySettings.tenancyLevel` is set to `TABLE` in the request. Primary key column of the client mapping table. **Required when** `tenancySettings.tenancyLevel` is set to `TABLE` in the request. Optional array of table relationships to define how tables in the datamart are connected. Relationships enable joins between tables for more complex queries. **Replaces all existing relationships:** When provided, the relationships array completely replaces all existing relationships. Include all relationships you want to keep. If omitted entirely, existing relationships remain unchanged. * Define how tables relate to each other (e.g., orders.customer\_id → customers.id) * Supports different join types and cardinalities * Useful for creating metrics that span multiple tables * Optional - omit this field to keep existing relationships unchanged Name of the parent table in the relationship. Column name in the parent table that participates in the relationship. Name of the child table in the relationship. Column name in the child table that participates in the relationship. A descriptive name for the relationship (e.g., "orders\_to\_customers"). The cardinality of the relationship. Must be one of: `ManyToMany`, `ManyToOne`, `OneToMany`, `OneToOne`. **Optional:** Can be omitted or set to `null` if not specified. The type of SQL join to use. Must be one of: `INNER JOIN`, `LEFT JOIN`, `RIGHT JOIN`, `FULL JOIN`. **Optional:** Can be omitted or set to `null` if not specified. ## Response The name of the updated datamart (same as the input datamartName) on success. Error object returned only when the request fails. Not included in successful responses. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Update Tables Only theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "demo-sales-default-1", "tableList": [ { "schemaName": "databrain_dev2", "name": "demo_sales", "clientColumn": "client id", "isHide": false, "columns": [ { "name": "client id", "alias": "id", "isHide": true }, { "name": "client name", "alias": "name", "isHide": true, "defaultSort": "ASC" }, { "name": "profit", "alias": "profit", "allowAggregate": true, "defaultAggregation": "SUM" } ] } ] }' ``` ```bash cURL - Update Tenancy Settings Only theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "clients", "tableClientNameColumn": "client_name", "tablePrimaryKeyColumn": "id" } }' ``` ```bash cURL - Update to Multi-Database Tenancy theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tenancySettings": { "tenancyLevel": "MULTI_DATABASE", "primaryDatabase": "core_analytics" } }' ``` ```bash cURL - Update Both Tables and Tenancy theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tableList": [ { "schemaName": "public", "name": "orders", "clientColumn": "tenant_id", "isHide": false, "columns": [ {"name": "order_id", "alias": "id", "isHide": false}, {"name": "customer_id", "isHide": false} ] } ], "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "NUMBER", "schemaName": "public", "tableName": "client_mapping", "tableClientNameColumn": "client_id", "tablePrimaryKeyColumn": "id" }, "relationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] }' ``` ```bash cURL - Update Relationships Only theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "relationships": [ { "parentTableName": "orders", "parentColumnName": "customer_id", "childTableName": "customers", "childColumnName": "id", "relationshipName": "orders_to_customers", "cardinality": "ManyToOne", "join": "LEFT JOIN" } ] }' ``` ```bash cURL - Add Custom Columns theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Customer Orders", "columns": [ { "name": "order_id", "alias": "id", "label": "Order ID" }, { "name": "quantity", "label": "Quantity" }, { "name": "unit_price", "alias": "total_revenue", "label": "Total Revenue", "isCustomColumn": true, "sql": "quantity * unit_price" }, { "name": "order_date", "alias": "order_year", "label": "Order Year", "isCustomColumn": true, "sql": "EXTRACT(YEAR FROM order_date)" }, { "name": "created_at", "label": "Created At", "isApplyTimezone": true } ] } ] }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datamartName: 'sales-analytics', tableList: [ { schemaName: 'public', name: 'orders', label: 'Customer Orders', clientColumn: 'tenant_id', columns: [ { name: 'order_id', alias: 'id', label: 'Order ID' }, { name: 'customer_id', label: 'Customer' }, { name: 'order_date', alias: 'date', label: 'Order Date' } ] } ] }) }); const result = await response.json(); if (result.error) { console.error('Update failed:', result.error.message); } else { console.log('Datamart updated:', result.id); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.put( 'https://api.usedatabrain.com/api/v2/data-app/datamarts', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'datamartName': 'sales-analytics', 'tableList': [ { 'schemaName': 'public', 'name': 'orders', 'label': 'Customer Orders', 'clientColumn': 'tenant_id', 'columns': [ {'name': 'order_id', 'alias': 'id', 'label': 'Order ID'}, {'name': 'customer_id', 'label': 'Customer'} ] } ], 'tenancySettings': { 'tenancyLevel': 'TABLE', 'clientColumnType': 'STRING', 'schemaName': 'public', 'tableName': 'client_mapping', 'tableClientNameColumn': 'client_id', 'tablePrimaryKeyColumn': 'id' }, 'relationships': [ { 'parentTableName': 'orders', 'parentColumnName': 'customer_id', 'childTableName': 'customers', 'childColumnName': 'id', 'relationshipName': 'orders_to_customers', 'cardinality': 'ManyToOne', 'join': 'LEFT JOIN' } ] } ) result = response.json() if result.get('error'): print(f"Update failed: {result['error']['message']}") else: print(f"Datamart updated: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Put.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { datamartName: 'sales-analytics', tableList: [ { schemaName: 'public', name: 'orders', label: 'Customer Orders', columns: [ { name: 'order_id', alias: 'id', label: 'Order ID' }, { name: 'customer_id', label: 'Customer' } ] } ] }.to_json response = http.request(request) result = JSON.parse(response.body) if result['error'] puts "Update failed: #{result['error']['message']}" else puts "Datamart updated: #{result['id']}" end ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type UpdateDatamartRequest struct { DatamartName string `json:"datamartName"` TableList []TableInfo `json:"tableList,omitempty"` TenancySettings *TenancySettings `json:"tenancySettings,omitempty"` } type TableInfo struct { SchemaName string `json:"schemaName,omitempty"` Name string `json:"name"` Label string `json:"label,omitempty"` Columns []ColumnInfo `json:"columns"` } type ColumnInfo struct { Name string `json:"name"` Alias string `json:"alias,omitempty"` Label string `json:"label,omitempty"` IsHide bool `json:"isHide,omitempty"` } type TenancySettings struct { TenancyLevel string `json:"tenancyLevel,omitempty"` ClientColumnType string `json:"clientColumnType,omitempty"` SchemaName string `json:"schemaName,omitempty"` TableName string `json:"tableName,omitempty"` TableClientNameColumn string `json:"tableClientNameColumn,omitempty"` TablePrimaryKeyColumn string `json:"tablePrimaryKeyColumn,omitempty"` } func main() { reqData := UpdateDatamartRequest{ DatamartName: "sales-analytics", TableList: []TableInfo{ { SchemaName: "public", Name: "orders", Label: "Customer Orders", Columns: []ColumnInfo{ {Name: "order_id", Alias: "id", Label: "Order ID"}, {Name: "customer_id", Label: "Customer"}, }, }, }, } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("PUT", "https://api.usedatabrain.com/api/v2/data-app/datamarts", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Datamart updated successfully") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics', 'tableList' => [ [ 'schemaName' => 'public', 'name' => 'orders', 'label' => 'Customer Orders', 'columns' => [ [ 'name' => 'order_id', 'alias' => 'id', 'label' => 'Order ID' ], [ 'name' => 'customer_id', 'label' => 'Customer' ] ] ] ] ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'PUT', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); if (isset($result['error'])) { echo "Update failed: " . $result['error']['message']; } else { echo "Datamart ID: " . $result['id']; } ?> ``` ```json 200 - Success theme={"dark"} { "id": "sales-analytics" } ``` ```json 400 - Datamart Not Found theme={"dark"} { "error": { "code": "INVALID_DATAMART", "message": "invalid datamart name." } } ``` ```json 400 - Invalid Table Structure theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid table or column structure" } } ``` ```json 400 - Invalid Schema or Table theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid schema or table name" } } ``` ```json 400 - Invalid Column Names theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid column names in table" } } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"datamartName\" is required" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal Server Error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Datamart updated successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ----------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid parameters | | `INVALID_DATAMART` | 400 | Datamart not found | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide Retrieve the existing datamart configuration before making changes: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts?isPagination=false' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Save this response in case you need to rollback your changes. Determine what you want to update: * **Tables/Columns**: Prepare the complete new tableList (replaces existing) * **Tenancy**: Prepare updated tenancySettings (optional) * **Both**: You can update both in a single request If only updating tenancy, omit the tableList field to keep existing tables intact. Make the update request: ```bash theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tableList": [ { "schemaName": "public", "name": "orders", "label": "Customer Orders", "clientColumn": "tenant_id", "columns": [ {"name": "order_id", "alias": "id"}, {"name": "customer_id"} ] } ] }' ``` Successful response returns the datamart name. Test that the datamart works correctly: * Load metrics that use this datamart * Check that all expected tables and columns are accessible * Verify tenancy is working if you updated those settings * Monitor for any errors in your dashboards If metrics break, you can update again with your saved previous configuration to rollback. ## Next Steps Create a new datamart from scratch View all datamarts in your organization Remove datamarts you no longer need Learn more about datamarts # Update Datasource Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-datasource PUT https://api.usedatabrain.com/api/v2/datasource Update the credentials and configuration of an existing datasource. The API validates and tests the new credentials before applying changes. Update an existing datasource's credentials or configuration. The API validates the new credentials, tests the connection, and automatically refreshes the cached schema. You can only update datasources that already exist in your organization. The datasource is identified by the `name` field in the credentials. After updating, the schema will be automatically re-cached. ## Endpoint ``` PUT https://api.usedatabrain.com/api/v2/datasource ``` ## Self-hosted Databrain Endpoint ``` PUT /api/v2/datasource ``` ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. ```bash Authentication theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' ``` ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The type of datasource. Must match the existing datasource type. See [Create Datasource](/developer-docs/helpers/api-reference/create-datasource) for supported types. Updated connection credentials for the datasource. Must include the `name` field matching the existing datasource name. The `credentials.name` field must match the exact name of the existing datasource you want to update. This name is used to identify which datasource to update. The name of the existing datasource to update. Must match exactly as it was created. * Use the [List Datasources API](/developer-docs/helpers/api-reference/list-datasources) to see all datasource names * Check the response from datasource creation * Available in the DataBrain dashboard when viewing datasources Multi-tenant configuration for the datasource. Defines how data is isolated between different tenants/clients. Optional - if not provided, existing tenancy settings will remain unchanged. * **TABLE level**: Uses a dedicated table to map client identifiers * **DATABASE level**: Each client has a separate database * If the datasource doesn't have existing tenancy settings, new settings will be created * If tenancy settings already exist, they will be updated with the new values The level at which tenant isolation occurs. Must be one of: `TABLE` or `DATABASE`. * `TABLE`: Client mapping is stored in a specific table (most common) * `DATABASE`: Each client has a separate database instance **Required when** `tenancySettings` is provided. If `tenancySettings` is omitted, this field is not needed. Data type of the client identifier column. Must be either `NUMBER` or `STRING`. **Required when** `tenancyLevel` is `TABLE`. Schema name where the client mapping table is located. **Required when** `tenancyLevel` is `TABLE`. Name of the table that contains client mapping information. **Required when** `tenancyLevel` is `TABLE`. Column name in the mapping table that stores the client identifier. **Required when** `tenancyLevel` is `TABLE`. Primary key column of the client mapping table. **Required when** `tenancyLevel` is `TABLE`. ### Datasource-Specific Credentials You must provide all required fields for the datasource type, even if only some values are changing. Partial updates are not supported. When updating credentials, provide the complete credential structure for the datasource type. Partial updates are not supported. Datasource-specific credential fields. The required fields depend on the `datasourceType`. Snowflake account hostname (e.g., `your-account.snowflakecomputing.com`) Snowflake username Snowflake role to use Snowflake warehouse name Snowflake database name Snowflake schema name Authentication method: `"username/password"` or `"Key-pair authentication"` Password (required if credentials is `"username/password"`) Private key (required if credentials is `"Key-pair authentication"`) Passphrase for the private key (optional) Database hostname or IP address Database port number (1-65535) Database username Database password Database name Schema name Enable SSL mode (optional) SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH server hostname (required if sshTunnel is `"enable"`) SSH server port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) CockroachDB hostname or IP address Database port number (1-65535) Database username Database password Database name Schema name Enable SSL mode (optional) SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH server hostname (required if sshTunnel is `"enable"`) SSH server port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) JSON string containing Google Cloud service account credentials Google Cloud project ID BigQuery dataset location (e.g., `"US"`, `"EU"`) BigQuery dataset ID (optional) Database hostname or IP address Database port number (1-65535) Database username. Note: Uses `user` not `username` for these datasource types. Database password SQL Server hostname or IP address. Note: Uses `server` not `host` for MSSQL. Database port number (1-65535) Database username. Note: Uses `user` not `username` for MSSQL. Database password Database name (optional) Disable database selection (optional) Optional MSSQL read-only routing hint. When `true`, Databrain connects with read-only intent for MSSQL workloads. Database hostname or IP address Database port number (1-65535) Database username Database password Database name Databricks server hostname Databricks HTTP path Databricks access token Server type: `"elastic-cloud"`, `"open-cloud"`, or `"self-managed"` Cloud ID (required if server\_type is `"elastic-cloud"` or `"open-cloud"`) Server URL (required if server\_type is `"self-managed"`) Username (required unless `disableAuth` is `true`) Password (required unless `disableAuth` is `true`) Disable authentication (optional, default `false`). Only valid when server\_type is `"self-managed"`. Ignore certificate verification (optional) Ignore SSL (optional) Server type: `"elastic-cloud"`, `"open-cloud"`, or `"self-managed"` Cloud ID (required if server\_type is `"elastic-cloud"` or `"open-cloud"`) Server URL (required if server\_type is `"self-managed"`) Username (required unless `disableAuth` is `true`) Password (required unless `disableAuth` is `true`) Disable authentication (optional, default `false`). Only valid when server\_type is `"self-managed"`. Ignore certificate verification (optional) Ignore SSL (optional) Firebolt client ID Firebolt client secret Firebolt account name Database name Engine name Schema name (optional) Athena database name S3 output bucket for query results AWS access key ID AWS region AWS secret access key Datasource ID (optional) Trino hostname or IP address Database port number (1-65535) Trino catalog name Schema name Username Password SSH tunnel setting: `"enable"` or `"disable"` (optional) SSH host (required if sshTunnel is `"enable"`) SSH port (required if sshTunnel is `"enable"`) SSH username (required if sshTunnel is `"enable"`) SSH private key (required if sshTunnel is `"enable"`) Name for the CSV datasource S3 bucket name Path within the bucket (optional, can be empty string) AWS region (e.g., `"us-east-1"`) Table level: `"File"` or `"Folder"` (optional) AWS access key ID AWS secret access key ## Response The name of the updated datasource (same as credentials.name). Error field, null when successful. Not included in successful responses. ## Examples ```bash cURL - PostgreSQL Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "postgres", "credentials": { "name": "production-postgres", "host": "new-db.example.com", "port": 5432, "username": "dbuser", "password": "newpassword", "database": "analytics", "schema": "public" } }' ``` ```bash cURL - Snowflake Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "snowflake", "credentials": { "name": "analytics-snowflake", "host": "account.snowflakecomputing.com", "username": "user@example.com", "role": "ANALYST", "warehouse": "COMPUTE_WH", "database": "ANALYTICS", "schema": "PUBLIC", "credentials": "username/password", "password": "updatedpassword" } }' ``` ```bash cURL - MSSQL Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "mssql", "credentials": { "name": "production-mssql", "server": "sqlserver.example.com", "port": 1433, "user": "sqluser", "password": "updatedpassword", "database": "analytics", "readOnlyIntent": true } }' ``` ```bash cURL - CockroachDB Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "cockroachdb", "credentials": { "name": "production-cockroachdb", "host": "cockroach.example.com", "port": 26257, "username": "dbuser", "password": "updatedpassword", "database": "analytics", "schema": "public" } }' ``` ```bash cURL - OpenSearch Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "opensearch", "credentials": { "name": "production-opensearch", "server_type": "self-managed", "server_url": "https://opensearch.example.com:9200", "username": "admin", "password": "updatedpassword" } }' ``` ```bash cURL - Elasticsearch Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "elasticsearch", "credentials": { "name": "production-elasticsearch", "server_type": "elastic-cloud", "cloud_id": "my-deployment:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyQ...", "username": "elastic", "password": "updatedpassword" } }' ``` ```bash cURL - Trino Example theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "trino", "credentials": { "name": "production-trino", "host": "trino.example.com", "port": 8080, "catalog": "hive", "schema": "analytics", "username": "trinouser", "password": "updatedpassword" } }' ``` ```bash cURL - Update With Tenancy Settings theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/datasource \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datasourceType": "postgres", "credentials": { "name": "production-postgres", "host": "db.example.com", "port": 5432, "username": "dbuser", "password": "newpassword", "database": "analytics", "schema": "public" }, "tenancySettings": { "tenancyLevel": "TABLE", "clientColumnType": "STRING", "schemaName": "public", "tableName": "clients", "tableClientNameColumn": "client_name", "tablePrimaryKeyColumn": "client_id" } }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/datasource', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datasourceType: 'postgres', credentials: { name: 'production-postgres', host: 'new-db.example.com', port: 5432, username: 'dbuser', password: 'newpassword', database: 'analytics', schema: 'public' } }) }); const data = await response.json(); if (data.error) { console.error('Error:', data.error); } else { console.log('Datasource updated:', data.name); } ``` ```python Python theme={"dark"} import requests response = requests.put( 'https://api.usedatabrain.com/api/v2/datasource', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'datasourceType': 'postgres', 'credentials': { 'name': 'production-postgres', 'host': 'new-db.example.com', 'port': 5432, 'username': 'dbuser', 'password': 'newpassword', 'database': 'analytics', 'schema': 'public' } } ) data = response.json() if data.get('error'): print('Error:', data['error']) else: print('Datasource updated:', data['name']) ``` ```json 200 - Success theme={"dark"} { "name": "production-postgres" } ``` ```json 400 - Bad Request theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid credentials for postgres: \"host\" is required", "status": 400 } } ``` ```json 400 - Datasource Not Found theme={"dark"} { "error": { "code": "DATASOURCE_NAME_ERROR", "message": "Invalid datasource name", "status": 400 } } ``` ```json 400 - Connection Test Failed theme={"dark"} { "error": { "code": "CREDENTIAL_TEST_FAILED", "message": "Failed to connect to datasource", "status": 400 } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "AUTHENTICATION_ERROR", "status": 401 } } ``` ```json 500 - Tenancy Settings Failed theme={"dark"} { "error": { "code": "TENANCY_SETTINGS_UPDATE_FAILED", "message": "Failed to update tenancy settings", "status": 500 } } ``` ## Error Codes | Error Code | HTTP Status | Description | | -------------------------------- | ----------- | ------------------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing required fields or invalid credential structure | | `DATASOURCE_NAME_ERROR` | 400 | Datasource not found | | `CREDENTIAL_TEST_FAILED` | 400 | Connection test failed | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing service token | | `SCHEMA_CACHE_FAILED` | 500 | Schema caching failed | | `DATASOURCE_NOT_FOUND` | 404 | The specified datasource does not exist | | `TENANCY_SETTINGS_CREATE_FAILED` | 500 | Failed to create tenancy settings for the datasource | | `TENANCY_SETTINGS_UPDATE_FAILED` | 500 | Failed to update existing tenancy settings | | `INTERNAL_SERVER_ERROR` | 500 | Server error occurred | ## Next Steps View all datasources to verify the update Manually sync the datasource schema if needed Create a new datasource instead of updating Remove a datasource you no longer need # Update an Embed Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-embed PUT https://api.usedatabrain.com/api/v2/data-app/embeds Update an existing embed to modify access settings, permissions, and datamart associations. Modify existing embeds to update access settings, change permissions, or associate with different datamarts. This allows you to evolve your embedded analytics without recreating configurations. **Endpoint Migration Notice:** We're transitioning to kebab-case endpoints. The new endpoint is `/api/v2/data-app/embeds`. The old endpoint `/api/v2/dataApp/embeds` will be deprecated soon. Please update your integrations to use the new endpoint format. Updates to embed configurations take effect immediately for all active embedded dashboards and metrics using this configuration. ## Endpoint Formats ``` PUT https://api.usedatabrain.com/api/v2/data-app/embeds ``` **Use this endpoint** for all new integrations. This is the recommended endpoint format. ``` POST https://api.usedatabrain.com/api/v2/dataApp/embed/update Content-Type: application/json { "embedId": "embed_abc123def456", "accessSettings": { ... } } ``` This endpoint still works but will be deprecated. Uses POST method with JSON body. ## Authentication All API requests must include your API key in the Authorization header. Get your API token when creating a data app - see our [data app creation guide](/guides/datasources/create-a-data-app) for details. **Finding your API token:** For detailed instructions, see the [API Token guide](/developer-docs/helpers/api-token). ```bash Authentication theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_...' \ --header 'Content-Type: application/json' ``` ## Headers Bearer token for API authentication. Use your API key from the data app. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body The unique identifier of the embed configuration to update. Get this from the create embed response or list embeds API. * Use the List All Embeds API to get embed IDs * Check the response from embed creation * Available in the DataBrain dashboard when viewing embed configurations Updated access control settings for the embedded view. Only provided fields will be updated. Change the datamart used by this embed configuration. Update AI Pilot permission. Update email reports permission. Update metrics management permission. Update metric creation permission. Update metric deletion permission. Update metric layout change permission. Update metric modification permission. Update underlying data access permission. Update dashboard view creation permission. Optional. Enable or disable end-user dashboard filter interactions. Optional allowlist for dashboard filterable columns. Each item must include `tableName` and `columns`. Fully qualified table name used in dashboard filters. Column names allowed for dashboard filter evaluation for the specified table. Optional. Enable or disable end-user metric filter interactions. Optional allowlist for columns that end users can use in metric filters. Each item must include `tableName` and `columns`. Fully qualified table name used in metric filters. Column names allowed for metric filter evaluation for the specified table. Recommended join strategy for table relationships. * `single`: single worksheet mode (tables are pre-joined into one worksheet) * `multi`: multi-sheet mode (joins are resolved dynamically based on fields used in each chart) Legacy join strategy flag. Prefer using `accessSettings.joinModel` instead. Update the metric creation mode. Update multi-tenant table access configuration. Table name for tenancy configuration. Column name for client-level filtering. ## Response The ID of the updated embed configuration. Error object if the request failed, otherwise `null` for successful requests. ## Examples ```bash cURL theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_abc123def456", "accessSettings": { "isAllowMetricCreation": false, "isAllowUnderlyingData": true, "isAllowEndUserDashboardFilter": true, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "joinModel": "multi", "tableTenancySettings": [ { "name": "updated_sales_data", "clientColumn": "customer_id" } ] } }' ``` ```javascript Node.js theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/embeds', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ embedId: 'embed_abc123def456', accessSettings: { isAllowMetricCreation: false, isAllowUnderlyingData: true, isAllowEndUserDashboardFilter: true, dashboardFilterColumns: [ { tableName: 'public.sales_data', columns: ['customer_id', 'region', 'order_date'] } ], isAllowEndUserMetricFilter: true, metricFilterColumns: [ { tableName: 'public.sales_data', columns: ['region', 'order_date'] } ], joinModel: 'multi', tableTenancySettings: [ { name: 'updated_sales_data', clientColumn: 'customer_id' } ] } }) }); const data = await response.json(); console.log('Updated embed ID:', data.id); ``` ```python Python theme={"dark"} import requests import json url = "https://api.usedatabrain.com/api/v2/data-app/embeds" headers = { "Authorization": "Bearer dbn_live_abc123...", "Content-Type": "application/json" } payload = { "embedId": "embed_abc123def456", "accessSettings": { "isAllowMetricCreation": False, "isAllowUnderlyingData": True, "isAllowEndUserDashboardFilter": True, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region", "order_date"] } ], "isAllowEndUserMetricFilter": True, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "joinModel": "multi", "tableTenancySettings": [ { "name": "updated_sales_data", "clientColumn": "customer_id" } ] } } response = requests.put(url, headers=headers, data=json.dumps(payload)) data = response.json() print(f"Updated embed ID: {data['id']}") ``` ```json Success Response theme={"dark"} { "id": "embed_abc123def456", "error": null } ``` ```json Error Response (404) theme={"dark"} { "error": { "code": "EMBED_NOT_FOUND", "message": "Embed configuration not found", "status": 404, "details": { "embedId": "embed_invalid", "workspace": "analytics-workspace" } } } ``` ```json Error Response (400) theme={"dark"} { "error": { "code": "INVALID_DATAMART", "message": "Specified datamart does not exist in workspace", "status": 400, "details": { "datamartName": "invalid-datamart", "workspace": "analytics-workspace" } } } ``` ## Error Codes **Embed configuration not found** - The specified embed ID doesn't exist in the workspace **Workspace not found** - The specified workspace doesn't exist or you don't have access **Invalid datamart** - The specified datamart doesn't exist in the workspace **Insufficient permissions** - You don't have permission to update this embed configuration **Invalid API key** - Check your API key in dashboard settings ## HTTP Status Code Summary | Status Code | Description | | ----------- | ----------------------------------------------------------- | | `200` | **OK** - Embed configuration updated successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `403` | **Forbidden** - Insufficient permissions to update | | `404` | **Not Found** - Embed configuration not found | | `409` | **Conflict** - Update conflicts with existing configuration | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ------------------------------------- | | `EMBED_NOT_FOUND` | 404 | Embed configuration not found | | `INVALID_WORKSPACE_NAME` | 404 | Workspace not found | | `INVALID_DATAMART` | 404 | Datamart not found | | `INSUFFICIENT_PERMISSIONS` | 403 | No permission to update | | `AUTHENTICATION_ERR` | 401 | Invalid API key | | `INVALID_ACCESS_SETTINGS` | 400 | Invalid access settings | | `CONFLICTING_UPDATE` | 409 | Update conflicts with existing config | | `RATE_LIMIT_EXCEEDED` | 429 | Too many requests | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Update Strategies Gradually increase permissions based on user needs: ```javascript theme={"dark"} // Enable metric creation for power users await updateEmbed({ embedId: 'embed_123', accessSettings: { isAllowMetricCreation: true, metricCreationMode: 'CHAT' } }); ``` Move embed to a different datamart: ```javascript theme={"dark"} await updateEmbed({ embedId: 'embed_123', accessSettings: { datamartName: 'new-datamart' } }); ``` Reduce permissions when needed: ```javascript theme={"dark"} await updateEmbed({ embedId: 'embed_123', accessSettings: { isAllowMetricDeletion: false, isAllowUnderlyingData: false } }); ``` ## Common Update Scenarios ### Enable Advanced Features ```javascript theme={"dark"} // Upgrade basic embed to include AI features await updateEmbed({ embedId: 'embed_basic', accessSettings: { isAllowEmailReports: true, metricCreationMode: 'CHAT' } }); ``` ### Migrate to New Datamart ```javascript theme={"dark"} // Move embed to updated datamart await updateEmbed({ embedId: 'embed_old', accessSettings: { datamartName: 'updated-sales-data', tableTenancySettings: [ { name: 'new_customer_table', clientColumn: 'tenant_id' } ] } }); ``` ### Temporary Permission Reduction ```javascript theme={"dark"} // Temporarily reduce permissions during maintenance await updateEmbed({ embedId: 'embed_maintenance', accessSettings: { isAllowMetricCreation: false, isAllowMetricUpdate: false, isAllowMetricDeletion: false } }); ``` ## Best Practices * Document all configuration changes * Test updates in staging first * Notify stakeholders of permission changes * Maintain change history and rollback plans * Follow principle of least privilege * Regular permission audits * Monitor for unauthorized changes * Validate datamart access before updates * Batch multiple updates when possible * Monitor embed performance after changes * Test with production data volumes * Update during low-usage periods * Communicate feature changes to users * Provide training for new capabilities * Gradual rollout of new permissions * Collect feedback on configuration changes ## Advanced Configuration ### Dynamic Permission Updates ```javascript theme={"dark"} // Update permissions based on user tier const updatePermissionsForTier = async (embedId, userTier) => { const permissions = { basic: { isAllowMetricCreation: false, isAllowUnderlyingData: false }, premium: { isAllowMetricCreation: true, isAllowUnderlyingData: true, metricCreationMode: 'CHAT' } }; await updateEmbed({ embedId, accessSettings: permissions[userTier] }); }; ``` ### Bulk Updates ```javascript theme={"dark"} // Update multiple embeds with same settings const bulkUpdateEmbeds = async (embedIds, updates) => { const promises = embedIds.map(embedId => updateEmbed({ embedId, accessSettings: updates }) ); const results = await Promise.all(promises); return results; }; ``` ## Quick Start Guide List your existing embed configurations to find the one you want to update: ```bash theme={"dark"} curl --request GET \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Update only the settings you want to change. For example, to enable End User Metric Creation: ```bash theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_abc123def456", "accessSettings": { "isAllowMetricCreation": true } }' ``` Change the datamart associated with your embed: ```bash theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/embeds \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "embedId": "embed_abc123def456", "accessSettings": { "datamartName": "new-datamart-name" } }' ``` The API will return the embed ID on success: ```javascript theme={"dark"} const updateResult = await updateEmbed({ embedId: 'embed_123', accessSettings: { isAllowMetricCreation: true } }); console.log('Updated embed ID:', updateResult.id); console.log('Success:', !updateResult.error); ``` ## Next Steps Remove embed configurations you no longer need View all embed configurations in your workspace Create tokens for your updated embed configurations Learn the basics of embedding DataBrain # Update Embedded Filter Alias Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-filter-alias Rename dashboard and metric filter labels for an embedded end user. Update the label shown for an existing dashboard or metric filter in an embedded experience. These are end-user plugin APIs: authenticate with a guest token in `X-Plugin-Token`, not with a Data App API key. Enable the matching rename permission in `params.accessPermissions` when you mint the guest token: `isAllowDashboardFilterNameChange` for dashboard filters or `isAllowMetricFilterNameChange` for metric filters. ## Endpoints ### Cloud Databrain ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/dashboard/updateDashboardFilterAlias POST https://api.usedatabrain.com/api/v2/dashboard/updateMetricFilterAlias ``` ### Self-hosted Databrain ```http theme={"dark"} POST /api/v2/dashboard/updateDashboardFilterAlias POST /api/v2/dashboard/updateMetricFilterAlias ``` ## Authentication Guest token generated by the [Guest Token API](/developer-docs/helpers/api-reference/token). The token determines the dashboard, metric, workspace, and client scope for the request. Must be set to `application/json`. ## Update a dashboard filter alias Dashboard identifier. The API accepts the dashboard's internal UUID or its external dashboard ID. Case-insensitive dashboard filter key in the form `tableName.columnName`, for example `public.sales_data.region`. The filter must already exist and must not be a client-created dashboard filter. New label for the filter. Leading and trailing whitespace is removed and the trimmed value can be at most 100 characters. Send an empty string to clear the alias. ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/dashboard/updateDashboardFilterAlias \ --header 'X-Plugin-Token: ' \ --header 'Content-Type: application/json' \ --data '{ "externalDashboard": "dashboard-uuid-or-external-id", "filterKey": "public.sales_data.region", "alias": "Sales region" }' ``` ## Update a metric filter alias Metric identifier. The API accepts the metric's internal UUID or metric ID. Case-insensitive metric filter key in the form `tableName.columnName`, for example `public.sales_data.region`. The filter must already exist. New label for the filter. Leading and trailing whitespace is removed and the trimmed value can be at most 100 characters. Send an empty string to clear the alias. ```bash cURL theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/dashboard/updateMetricFilterAlias \ --header 'X-Plugin-Token: ' \ --header 'Content-Type: application/json' \ --data '{ "externalMetricId": "metric-uuid-or-id", "filterKey": "public.sales_data.region", "alias": "Sales region" }' ``` ## Response Both endpoints return the updated alias in the `data` object: ```json theme={"dark"} { "data": { "id": "alias_abc123", "filterKey": "public.sales_data.region", "alias": "Sales region" } } ``` When `alias` is an empty string, the endpoint removes the stored alias and returns: ```json theme={"dark"} { "data": { "filterKey": "public.sales_data.region", "alias": "" } } ``` ## Status codes | Status | Description | | ------ | ----------------------------------------------------------------------------------------------------------------------- | | `200` | Alias updated or cleared successfully. | | `400` | Missing or invalid body fields, an unknown filter, or an alias longer than 100 characters. | | `403` | The guest token is not authorized for the requested dashboard or metric, or the matching rename permission is disabled. | | `404` | The dashboard or metric was not found in the guest token's authorized scope. | | `500` | The alias could not be persisted or an unexpected server error occurred. | # Update Semantic Layer Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-semantic-layer PUT https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer Update the semantic layer for a datamart by modifying table descriptions, column metadata, or feedback. Modify the semantic layer metadata for an existing datamart. You can update table descriptions, column metadata, and feedback in a single request. Only the fields you include are updated — omitted tables and columns retain their existing values. The datamart must already have a semantic layer. If no semantic data exists, this endpoint returns `404 SEMANTIC_LAYER_NOT_FOUND`. Use [POST](/developer-docs/helpers/api-reference/create-semantic-layer) to create a semantic layer first. ## Authentication This endpoint requires a **service token** in the Authorization header. Data app API tokens are not permitted and will be rejected with a `403` error. To access your service token: 1. Go to your Databrain dashboard and open **Settings**. 2. Navigate to **Settings**. 3. Find the **Service Tokens** section. 4. Click the **"Generate Token"** button to generate a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the existing datamart to update. Must match exactly (case-sensitive). Array of table objects with updated semantic metadata. Only tables and columns included in the request are modified — others remain unchanged. Table name from the datamart. Must match an existing table. Updated description for the table. Maximum 500 characters. Updated synonyms for the table. Maximum 10 synonyms, each up to 100 characters. Must be unique (case-insensitive). Updated additional context. Maximum 1000 characters. Array of column objects to update. Only listed columns are modified. Column name from the table. Must match an existing column. Updated description. Maximum 500 characters. Updated synonyms. Maximum 10 synonyms, each up to 100 characters. Updated additional context. Maximum 1000 characters. Updated semantic column type. Must be one of: `String`, `Long String`, `String (Custom)`, `ENUM`, `Mapper`, `Range`, `Expression`, `Identifier`, `Number`, `JSON`. Must be compatible with the column's underlying datatype. Updated configuration for the column type. Same shapes as [create](/developer-docs/helpers/api-reference/create-semantic-layer): object map for `String` / `String (Custom)` / `ENUM` / `Mapper`; `{ lowerLimit, upperLimit }` (numbers) for `Range`; string for `Expression` and `JSON`; `null` or omit for `Identifier`, `Number`, and `Long String`. Updated identifier flag. Updated indexing exclusion flag. Updated global feedback text. Maximum 2000 characters. When provided, replaces the existing feedback. ## Response On success, the response body contains only the datamart name. There is no `error` field in the JSON body when the request succeeds. The name of the updated datamart (same as the input `datamartName`). ## Examples ```bash cURL - Update Tables & Feedback theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "tables": [ { "name": "orders", "description": "Updated: Customer purchase orders with status tracking", "columns": [ { "name": "status", "description": "Order lifecycle status", "synonyms": ["order status", "state", "order state"] } ] } ], "feedback": "Updated context: All amounts in USD. Fiscal year starts April 1." }' ``` ```bash cURL - Update Feedback Only theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "feedback": "Updated: All amounts in USD. Customer IDs are numeric." }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ datamartName: 'sales-analytics', tables: [ { name: 'orders', description: 'Updated order descriptions', columns: [ { name: 'status', description: 'Order lifecycle status', synonyms: ['order status', 'state'] } ] } ], feedback: 'Updated feedback text.' }) }); const result = await response.json(); if (result.error) { console.error('Update failed:', result.error.message); } else { console.log('Semantic layer updated:', result.id); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.put( 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'datamartName': 'sales-analytics', 'tables': [ { 'name': 'orders', 'description': 'Updated order descriptions', 'columns': [ { 'name': 'status', 'description': 'Order lifecycle status', 'synonyms': ['order status', 'state'] } ] } ], 'feedback': 'Updated feedback text.' } ) result = response.json() if result.get('error'): print(f"Update failed: {result['error']['message']}") else: print(f"Semantic layer updated: {result['id']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Put.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { datamartName: 'sales-analytics', tables: [ { name: 'orders', description: 'Updated order descriptions', columns: [ { name: 'status', description: 'Order lifecycle status' } ] } ] }.to_json response = http.request(request) result = JSON.parse(response.body) puts "Updated: #{result['id']}" ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class UpdateSemanticLayer { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "datamartName": "sales-analytics", "tables": [ { "name": "orders", "description": "Updated order descriptions", "columns": [ { "name": "status", "description": "Order lifecycle status" } ] } ], "feedback": "Updated feedback text." }"""; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) func main() { body := map[string]interface{}{ "datamartName": "sales-analytics", "tables": []map[string]interface{}{ { "name": "orders", "description": "Updated order descriptions", "columns": []map[string]interface{}{ { "name": "status", "description": "Order lifecycle status", }, }, }, }, "feedback": "Updated feedback text.", } jsonData, _ := json.Marshal(body) req, _ := http.NewRequest("PUT", "https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Semantic layer updated") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'sales-analytics', 'tables' => [ [ 'name' => 'orders', 'description' => 'Updated order descriptions', 'columns' => [ [ 'name' => 'status', 'description' => 'Order lifecycle status' ] ] ] ], 'feedback' => 'Updated feedback text.' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'PUT', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); echo "Updated: " . $result['id']; ?> ``` ```json 200 - Success theme={"dark"} { "id": "sales-analytics" } ``` ```json 400 - Missing datamartName theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"datamartName\" is required" } } ``` ```json 400 - No Section Provided theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"value\" must contain at least one of [tables, feedback]" } } ``` ```json 400 - Invalid Table theme={"dark"} { "error": { "code": "INVALID_TABLE", "message": "Table 'nonexistent_table' not found in datamart 'sales-analytics'" } } ``` ```json 404 - No Semantic Layer theme={"dark"} { "error": { "code": "SEMANTIC_LAYER_NOT_FOUND", "message": "No semantic layer found for datamart 'sales-analytics'. Use POST to create first." } } ``` ```json 403 - Data App Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Semantic Layer API requires a service token, not a data app API token" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------------------ | | `200` | **OK** — Semantic layer updated successfully | | `400` | **Bad Request** — Validation failed (see error codes below) | | `401` | **Unauthorized** — Invalid or missing API token | | `403` | **Forbidden** — Data app token used instead of service token | | `404` | **Not Found** — No semantic layer exists for this datamart | | `500` | **Internal Server Error** — Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | ---------------------------- | ----------- | --------------------------------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing required fields or validation failure | | `INVALID_DATAMART` | 400 | Datamart not found | | `INVALID_TABLE` | 400 | Table name doesn't exist in the datamart | | `INVALID_COLUMN` | 400 | Column name doesn't exist in the table | | `INVALID_COLUMN_TYPE` | 400 | Column type incompatible with the column's datatype | | `INVALID_COLUMN_TYPE_CONFIG` | 400 | Column type config has wrong shape | | `DUPLICATE_SYNONYM` | 400 | Duplicate synonyms detected (case-insensitive) | | `SEMANTIC_LAYER_NOT_FOUND` | 404 | No semantic layer exists — use POST to create first | | `AUTHENTICATION_ERROR` | 403 | Data app token used instead of service token | | `INTERNAL_SERVER_ERROR` | 500 | Server error | ## Quick Start Guide Retrieve the existing semantic layer before making changes: ```bash theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer?datamartName=sales-analytics' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` Save this response in case you need to rollback your changes. Determine what you want to update: * **Tables/Columns**: Include only the tables and columns you want to change * **Feedback**: Provide the new text (replaces existing) Unlike the datamart update API, the semantic layer update is additive for tables and columns — only the ones you include are modified. ```bash theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/data-app/datamarts/semantic-layer \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "datamartName": "sales-analytics", "feedback": "Updated context." }' ``` Retrieve the semantic layer again to confirm changes and check the updated completion score. ## Next Steps Retrieve and verify your changes Create a semantic layer for a new datamart Remove semantic layer metadata entirely Configure the semantic layer in the Databrain UI # Update Workspace Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-workspace PUT https://api.usedatabrain.com/api/v2/workspace Update an existing workspace's connection settings to change datasource, datamart, multi-datasource, or multi-datamart configuration. Update the connection settings of an existing workspace. You can switch between datasource, datamart, multi-datasource, and multi-datamart configurations. Updating a workspace also updates all associated metrics to use the new connection. **Important:** Updating a workspace connection will automatically update all metrics in that workspace to use the new datasource or datamart connection. Ensure the new connection has compatible table and column structures to avoid breaking existing metrics. The workspace name is used to identify which workspace to update and cannot be changed through this endpoint. To rename a workspace, you'll need to create a new one and migrate your content. ## Authentication This endpoint requires a service token in the Authorization header. Service tokens differ from data app API keys and provide organization-level permissions. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click the **"Generate Token"** button to create a new service token if you don't have one already. Use this token as the Bearer value in your Authorization header. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json` for all requests. ``` Content-Type: application/json ``` ## Request Body Name of the existing workspace to update. Must match exactly (case-sensitive). * Use the [List Workspaces API](/developer-docs/helpers/api-reference/list-workspaces) to get all workspace names * Names are case-sensitive and must match exactly * This field identifies which workspace to update New connection type for the workspace. Must be one of: `DATASOURCE`, `DATAMART`, `MULTI_DATASOURCE`, or `MULTI_DATAMART`. * **DATASOURCE**: Connect directly to a single datasource * **DATAMART**: Connect to a pre-configured datamart * **MULTI\_DATASOURCE**: Allow connections to multiple datasources within this workspace * **MULTI\_DATAMART**: Allow switching between multiple datamarts within this workspace **Note:** Changing connection type will update all metrics in this workspace. For `MULTI_DATASOURCE` or `MULTI_DATAMART`, `datasourceName` and `datamartName` are optional; the API clears prior single-datasource or single-datamart links and enables the selected multi mode. For `DATASOURCE` or `DATAMART`, `datasourceName` or `datamartName` is required (respectively), and multi-datasource / multi-datamart modes are turned off. Name of the datasource to connect to this workspace. **Required when** `connectionType` is `DATASOURCE`. * Must be an existing datasource in your organization * Use the exact name as stored in datasource credentials * Names are case-sensitive * All metrics will be updated to use this datasource Name of the datamart to connect to this workspace. **Required when** `connectionType` is `DATAMART`. * Must be an existing datamart in your organization * Use the [List Datamarts API](/developer-docs/helpers/api-reference/list-datamarts) to find available datamarts * Names are case-sensitive * All metrics will be updated to use this datamart's datasource Optional primary LLM name for workspace-level AI features. Must match an existing LLM configured in your organization. Optional list of LLM names available for AI Copilot in this workspace. Every value must match an existing organization LLM name. Optional flag to enable or disable AI-powered metric suggestions for this workspace. Optional flag to enable or disable AI-generated metric summaries for this workspace. Summary mode used when metric summaries are enabled. Must be one of: `technicalAndInsightSummary`, `forecastAndTrendAnalysis`, `comparativeAndAnomalyDetection`, `custom`. **Required when** `isEnableMetricSummary` is `true`. Custom summary instruction prompt for AI-generated summaries. **Required when** `summaryType` is `custom`. Optional workspace theme name. Must match an existing theme configured in your organization. ## Response Contains the updated workspace information on success. The name of the successfully updated workspace. Error object if the request failed, otherwise `null` for successful requests. Error code identifying the type of error. Human-readable error message describing what went wrong. ## Examples ```bash cURL - Switch to Datasource theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "DATASOURCE", "datasourceName": "postgres-production" }' ``` ```bash cURL - Switch to Datamart theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "DATAMART", "datamartName": "sales-datamart" }' ``` ```bash cURL - Switch to Multi-Datasource theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "MULTI_DATASOURCE" }' ``` ```bash cURL - Switch to Multi-Datamart theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "MULTI_DATAMART" }' ``` ```bash cURL - Update AI + Theme Settings theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "name": "Sales Analytics", "connectionType": "DATAMART", "datamartName": "sales-datamart", "llmName": "gpt-4o", "aiCopilotLlms": ["gpt-4o", "gpt-4.1-mini"], "isEnableMetricSuggestions": true, "isEnableMetricSummary": true, "summaryType": "custom", "customSummaryPrompt": "Summarize weekly KPI shifts with root-cause hypotheses.", "themeName": "Executive Theme" }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ name: 'Sales Analytics', connectionType: 'DATASOURCE', datasourceName: 'postgres-production' }) }); const result = await response.json(); if (result.error) { console.error('Update failed:', result.error.message); } else { console.log('Workspace updated:', result.data.name); } ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.put( 'https://api.usedatabrain.com/api/v2/workspace', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'name': 'Sales Analytics', 'connectionType': 'DATASOURCE', 'datasourceName': 'postgres-production' } ) result = response.json() if result.get('error'): print(f"Update failed: {result['error']['message']}") else: print(f"Workspace updated: {result['data']['name']}") ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/workspace') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Put.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { name: 'Sales Analytics', connectionType: 'DATASOURCE', datasourceName: 'postgres-production' }.to_json response = http.request(request) result = JSON.parse(response.body) if result['error'] puts "Update failed: #{result['error']['message']}" else puts "Workspace updated: #{result['data']['name']}" end ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class UpdateWorkspace { public static void main(String[] args) throws Exception { HttpClient client = HttpClient.newHttpClient(); String requestBody = """ { "name": "Sales Analytics", "connectionType": "DATASOURCE", "datasourceName": "postgres-production" } """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/workspace")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "fmt" "net/http" ) type WorkspaceUpdateRequest struct { Name string `json:"name"` ConnectionType string `json:"connectionType"` DatasourceName string `json:"datasourceName,omitempty"` DatamartName string `json:"datamartName,omitempty"` } func main() { reqData := WorkspaceUpdateRequest{ Name: "Sales Analytics", ConnectionType: "DATASOURCE", DatasourceName: "postgres-production", } jsonData, _ := json.Marshal(reqData) req, _ := http.NewRequest("PUT", "https://api.usedatabrain.com/api/v2/workspace", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Workspace updated successfully") } ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'Sales Analytics', 'connectionType' => 'DATASOURCE', 'datasourceName' => 'postgres-production' ]; $options = [ 'http' => [ 'header' => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], 'method' => 'PUT', 'content' => json_encode($data) ] ]; $context = stream_context_create($options); $response = file_get_contents($url, false, $context); $result = json_decode($response, true); if (isset($result['error'])) { echo "Update failed: " . $result['error']['message']; } else { echo "Workspace updated: " . $result['data']['name']; } ?> ``` ```json 200 - Success theme={"dark"} { "data": { "name": "Sales Analytics" }, "error": null } ``` ```json 400 - Workspace Not Found theme={"dark"} { "error": { "code": "WORKSPACE_DOES_NOT_EXIST", "message": "Workspace does not exist" } } ``` ```json 400 - Invalid Datasource theme={"dark"} { "error": { "code": "INVALID_DATASOURCE_NAME", "message": "Invalid datasource name provided" } } ``` ```json 400 - Invalid Datamart theme={"dark"} { "error": { "code": "INVALID_DATAMART_NAME", "message": "Invalid datamart name provided" } } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"connectionType\" is required" } } ``` ```json 401 - Unauthorized theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ```json 500 - Server Error theme={"dark"} { "error": { "code": "INTERNAL_SERVER_ERROR", "message": "Internal Server Error" } } ``` ## HTTP Status Code Summary | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Workspace updated successfully | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `500` | **Internal Server Error** - Server error occurred | ## Possible Errors | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ----------------------------- | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid parameters | | `WORKSPACE_DOES_NOT_EXIST` | 400 | Workspace not found | | `INVALID_DATASOURCE_NAME` | 400 | Datasource not found | | `INVALID_DATAMART_NAME` | 400 | Datamart not found | | `INVALID_LLM_NAME` | 400 | Invalid LLM name provided | | `INVALID_AI_COPILOT_LLMS` | 400 | Invalid AI Copilot LLM list | | `INVALID_THEME_NAME` | 400 | Invalid theme name provided | | `INVALID_DATA_APP_API_KEY` | 401 | Invalid API key | | `INTERNAL_SERVER_ERROR` | 500 | Server error | # Update Workspace Dashboards Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/update-workspace-dashboards PUT https://api.usedatabrain.com/api/v2/workspace/dashboards Update filter mappings and dashboard gallery metrics for one or more dashboards inside a workspace. Update dashboard filter-to-table mappings and incrementally add or remove metrics from dashboard galleries for dashboards that belong to a workspace. **First-time workspace dashboard integration:** If you are wiring this flow for the first time, complete provisioning before calling this endpoint: 1. **Create an embed:** Set up embedding with [Create Embed](/developer-docs/helpers/api-reference/create-embed) or [Create Dashboard Embed](/developer-docs/helpers/api-reference/create-dashboard-embed). 2. **List embeds:** Use [List Embeds](/developer-docs/helpers/api-reference/list-embed) to verify metadata configurations and identify the created embed. 3. **Update:** Call [Update Workspace Dashboards](/developer-docs/helpers/api-reference/update-workspace-dashboards) with the dashboard ID and filter labels from the embed metadata. Skipping these steps often leads to unknown dashboard IDs or filter names that do not match anything on the dashboard, in which case the request fails validation. This endpoint updates existing dashboard filters by filter name. For each dashboard, DataBrain matches each input filter `name` against existing filter labels. Every requested filter name must match an existing filter label or the request fails validation. Each dashboard entry must include at least one operation: `filters`, `appendMetrics`, or `removedMetrics`. The `dashboards` array and each dashboard's `dashboardId` are required. `filters` is optional, but each filter must include `applyOnTables`; `appendMetrics` and `removedMetrics` are also optional. Metric gallery updates require a service token. A data app API token can be used for filter mapping updates, but requests containing `appendMetrics` or `removedMetrics` must use a service token. ## Authentication This endpoint requires an authorized API token in the Authorization header. Use a service token for dashboard gallery metric updates; filter mapping updates can also use a data app API token. To access your service token: 1. In **Settings** page, navigate to the **Service Tokens** section. 2. Click **Generate Token** to create a service token if you do not have one. ## Headers Bearer token for API authentication. Use your service token. ``` Authorization: Bearer dbn_live_abc123... ``` Must be set to `application/json`. ``` Content-Type: application/json ``` ## Request Body Name of the workspace containing the dashboards to update. List of dashboard update payloads. Dashboard IDs must be unique within this array. External dashboard ID to update. Optional list of filters to update for this dashboard. Filter name to match against the existing dashboard filter label. List of table/column targets where this filter should apply. Datatype of the target column. This required string is passed through to the dashboard filter mapping. Schema name of the target table. Table name without schema. Target column name. Optional list of workspace metric IDs to add to this dashboard's gallery. Workspace metric ID to add to the dashboard gallery. Each `metricId` may appear only once within `appendMetrics`. Optional list of dashboard gallery metric IDs to remove from this dashboard. Each ID may appear only once. Dashboard gallery metric ID to remove. A metric ID cannot be included in both `appendMetrics` and `removedMetrics` for the same dashboard. Internally, DataBrain stores table references as `schemaName.tableName` while preserving the provided `columnName`. When appending a workspace metric, DataBrain creates or reuses the dashboard-gallery copy for the dashboard's client. When removing a metric, only its association with the requested dashboard gallery is removed. ## Response Success payload. Returns `true` when all requested dashboard updates succeed. Error object if the request fails, otherwise `null`. ## Examples ```bash cURL theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "sales-workspace", "dashboards": [ { "dashboardId": "db_12345", "filters": [ { "name": "Region", "applyOnTables": [ { "dataType": "string", "schemaName": "public", "tableName": "orders", "columnName": "region" } ] } ] }, { "dashboardId": "db_67890", "filters": [ { "name": "Created Date", "applyOnTables": [ { "dataType": "date", "schemaName": "analytics", "tableName": "events", "columnName": "created_at" } ] } ] } ] }' ``` ```bash cURL - Update dashboard gallery metrics theme={"dark"} curl --request PUT \ --url https://api.usedatabrain.com/api/v2/workspace/dashboards \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "workspaceName": "sales-workspace", "dashboards": [ { "dashboardId": "db_12345", "appendMetrics": [ { "metricId": "metric_revenue" } ], "removedMetrics": [ "metric_old_gallery_copy" ] } ] }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/workspace/dashboards', { method: 'PUT', headers: { Authorization: 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ workspaceName: 'sales-workspace', dashboards: [ { dashboardId: 'db_12345', filters: [ { name: 'Region', applyOnTables: [ { dataType: 'string', schemaName: 'public', tableName: 'orders', columnName: 'region' } ] } ] } ] }) }); const result = await response.json(); console.log(result); ``` ```json 200 - Success theme={"dark"} { "data": { "success": true }, "error": null } ``` ```json 400 - Validation Error theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "\"dashboards\" is required" } } ``` ```json 400 - Invalid Dashboard theme={"dark"} { "error": { "code": "INVALID_DASHBOARD_ID", "message": "Dashboard with id db_12345 not found" } } ``` ```json 400 - Unknown Filter theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Filter name(s) not found for dashboard db_12345: Region" } } ``` ```json 403 - Gallery Metrics Require Service Token theme={"dark"} { "error": { "code": "AUTHENTICATION_ERROR", "message": "Dashboard gallery metric updates require a service token, not a data app API token." } } ``` ## Possible Errors | Error Code | HTTP Status | Description | | ----------------------- | ----------- | ------------------------------------------------------------------------------------------ | | `INVALID_REQUEST_BODY` | 400 | Missing or invalid fields in request body | | `INVALID_SERVICE_TOKEN` | 400 | Missing or invalid service token context | | `WORKSPACE_ID_ERROR` | 400 | Workspace does not exist for the authenticated organization | | `INVALID_DASHBOARD_ID` | 400 | Dashboard does not exist in the given workspace | | `INVALID_METRIC_ID` | 400 | A metric to append or remove is not available in the requested dashboard gallery context | | `AUTHENTICATION_ERROR` | 403 | Gallery metric updates were attempted with a data app API token instead of a service token | | `INTERNAL_SERVER_ERROR` | 500 | Unexpected server error | ## HTTP Status Code Summary | Status Code | Description | | ----------- | ---------------------------------------------------------------------------------------- | | `200` | **OK** - Requested dashboard filter and/or gallery metric updates completed successfully | | `400` | **Bad Request** - Validation failure, invalid token context, or invalid dashboard | | `403` | **Forbidden** - Gallery metric updates require a service token | | `500` | **Internal Server Error** - Unexpected server error | ## Next Steps Verify workspace names before update calls Validate downstream metric behavior after dashboard filter updates # Whitelist Domains Source: https://docs.usedatabrain.com/developer-docs/helpers/api-reference/whitelist-domains GET https://api.usedatabrain.com/api/v2/data-app/whitelist-domains Retrieve or update the account-wide list of domains allowed to embed your dashboards (GET to list, PUT to update). Manage the domains that are allowed to load embedded dashboards and metrics. Use **GET** to retrieve the current list and **PUT** to update it. Domain whitelisting is a security feature. Requests from non-whitelisted origins are rejected even with a valid API key or guest token. See [Domain Whitelisting](/developer-docs/security#domain-whitelisting) for more context. The whitelist is stored **account-wide**: although this endpoint is authenticated with a Data App API key, it reads and writes the single list shared by **all** Data Apps in your account. A `PUT` replaces the whole account's whitelist — include every domain used by every Data App, not just the one whose key you're using. ## Endpoints ``` GET https://api.usedatabrain.com/api/v2/data-app/whitelist-domains ``` Returns the account-wide list of whitelisted domains (shared by all Data Apps). ``` PUT https://api.usedatabrain.com/api/v2/data-app/whitelist-domains Content-Type: application/json { "domains": ["app.example.com", "*.customer.com"] } ``` Replaces the account-wide whitelist with the given array of domains. Supports domain names, wildcards (e.g. `*.example.com`), IPs with optional port, and `localhost` with optional port. ## Authentication All requests must include your **data app API key** in the `Authorization` header. See the [data app creation guide](/guides/datasources/create-a-data-app) and the [API Token guide](/developer-docs/helpers/api-token). ## Headers Bearer token for API authentication. Use your data app API key. ``` Authorization: Bearer dbn_live_abc123... ``` Required for PUT only. Must be `application/json`. ## GET – Query parameters None. ## PUT – Request Body Array of domain strings. Each entry must be one of: * A valid domain with at least two labels (e.g. `app.example.com`) * A wildcard subdomain (e.g. `*.example.com`) * An IPv4 address with optional port (e.g. `192.168.1.1` or `192.168.1.1:3000`) * `localhost` with optional port (e.g. `localhost` or `localhost:8080`) Do **not** include `http://` or `https://`. Pass an empty array `[]` to clear all whitelisted domains. ## Response ### GET response Array of whitelisted domain strings. Empty array if none are set. ### PUT response The saved list of whitelisted domains. ## Examples ```bash cURL theme={"dark"} curl --request GET \ --url 'https://api.usedatabrain.com/api/v2/data-app/whitelist-domains' \ --header 'Authorization: Bearer dbn_live_abc123...' ``` ```bash cURL theme={"dark"} curl --request PUT \ --url 'https://api.usedatabrain.com/api/v2/data-app/whitelist-domains' \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{"domains": ["app.example.com", "*.customer.com", "localhost:3000"]}' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} // List const listRes = await fetch('https://api.usedatabrain.com/api/v2/data-app/whitelist-domains', { method: 'GET', headers: { 'Authorization': 'Bearer dbn_live_abc123...' } }); const { data: domains } = await listRes.json(); // Update await fetch('https://api.usedatabrain.com/api/v2/data-app/whitelist-domains', { method: 'PUT', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json', }, body: JSON.stringify({ domains: ['app.example.com', '*.customer.com'] }), }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests headers = {"Authorization": "Bearer dbn_live_abc123..."} # List r = requests.get("https://api.usedatabrain.com/api/v2/data-app/whitelist-domains", headers=headers) domains = r.json().get("data", []) # Update requests.put( "https://api.usedatabrain.com/api/v2/data-app/whitelist-domains", headers={**headers, "Content-Type": "application/json"}, json={"domains": ["app.example.com", "*.customer.com"]}, ) ``` ```json GET – Success theme={"dark"} { "data": ["app.example.com", "*.customer.com", "localhost:3000"] } ``` ```json PUT – Success theme={"dark"} { "data": { "domains": ["app.example.com", "*.customer.com"] } } ``` ```json Error – Invalid body (PUT) theme={"dark"} { "error": { "code": "INVALID_REQUEST_BODY", "message": "Invalid domain format. Please enter domain/IP without http:// or https://" } } ``` ```json Error – Invalid API key theme={"dark"} { "error": { "code": "INVALID_DATA_APP_API_KEY", "message": "invalid or expired API KEY, data app not found" } } ``` ## Error codes | Error Code | HTTP Status | Description | | -------------------------- | ----------- | ----------------------------------------------------------------------- | | `INVALID_DATA_APP_API_KEY` | 400 | Missing or invalid data app API key | | `INVALID_SERVICE_TOKEN` | 400 | Invalid or expired token; cannot resolve company context | | `INVALID_REQUEST_BODY` | 400 | Invalid or malformed `domains` (e.g. protocol included, invalid format) | | `INTERNAL_SERVER_ERROR` | 500 | Unexpected server error | ## Related Security and whitelist behavior Configure email (e.g. scheduled reports) # API Token Source: https://docs.usedatabrain.com/developer-docs/helpers/api-token Generating API Token in DataBrain Navigate to the **Data tab > Data Apps** and then click on **New Data App** button. This modal will appear: Provide a relevant name and select DataApp Type as **embedded** and click on save. You will be navigated to the below screen. Then, proceed to the **API Token tab** and click on **Generate Token**. You'll be prompted to provide a **Name** and **Description** for your token. Once it's generated, you can conveniently copy the token for your use. # Component Options Reference Source: https://docs.usedatabrain.com/developer-docs/helpers/component-options-reference Comprehensive reference guide for all available options and properties for Databrain web components Try out the components with different options in DataBrain's playground This reference guide provides detailed documentation for all available options and properties for Databrain's web components: `dbn-dashboard` and `dbn-metric`. *** ## Understanding the Configuration Layers Databrain components have **four configuration layers** that are applied in a specific priority order. Understanding this hierarchy is essential for getting the behavior you expect. Settings are resolved from **highest priority** (top) to **lowest priority** (bottom). A higher-priority layer always wins when the same setting exists in multiple layers. | Priority | Layer | Scope | Prop | When to Use | | ----------- | ------------------------- | ---------------------------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- | | 1 (highest) | **Chart Appearance** | Per-metric (on `dbn-metric`) | `chart-appearance` | Fine-tune visual styling (margins, axis labels, legend position, tooltip fonts) for a single metric. | | 2 | **Admin Theme Options** | Global (on `dbn-dashboard`) | `admin-theme-options` | Apply org-wide branding: fonts, card styles, color palettes, dashboard background. | | 3 | **Custom Chart Settings** | Per-metric defaults (on `dbn-dashboard`) | `custom-chart-settings` | Set default chart behaviors (axis visibility, bar width, sort, zoom) and lock/unlock end-user editing via `canEdit`. | | 4 (lowest) | **Saved Metric Settings** | Per-metric (stored in DB) | N/A | Settings saved by the metric creator in the Databrain admin UI. | **`chart-appearance` vs `custom-chart-settings` field names differ.** These two layers evolved independently and use different keys for overlapping concepts. See the [Field Name Mapping](#field-name-mapping) table below for a cross-reference. **`custom-chart-settings` only applies to newly created metrics.** If a metric already exists in the database with saved settings, the `custom-chart-settings` prop will **not** override those saved values. This is by design — `custom-chart-settings` provides defaults for metric creation, not runtime overrides. To override settings on existing metrics, use `chart-appearance` instead. *** ## Dashboard Component (`dbn-dashboard`) The dashboard component displays a complete dashboard with multiple metrics and interactive features. ### Required Properties Guest token for authentication. Must be generated from your backend using the Databrain API. Unique identifier for the dashboard to display. ### Display & Layout Options Hides the table preview in full screen view. Hides chart settings in full screen view. Disables the full screen option for the dashboard. Enables fullscreen mode when the metric title is clicked. Provides an alternative way for users to enter fullscreen without using the fullscreen button. Controls which options icon to display. Options: `kebab-menu-vertical` | `download` Makes dashboard filters sticky at the top when scrolling. Controls the visibility and configuration of the settings icon. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { name: 'random', iconSvg: 'svg', menuPosition: 'bottom-start', // optional; defaults to "bottom-start" } ``` Custom label text for the settings button. Custom SVG markup for the settings button icon. Controls where the settings menu popup is anchored relative to the settings button. Options: `"auto"` | `"auto-start"` | `"auto-end"` | `"top"` | `"bottom"` | `"right"` | `"left"` | `"top-start"` | `"top-end"` | `"bottom-start"` | `"bottom-end"` | `"right-start"` | `"right-end"` | `"left-start"` | `"left-end"` Enables CSV download option in metric card actions. Enables email CSV option in metric card actions. Disables PNG download option in full screen mode. Enables download option for all metrics at once. Enables PDF download option for all metrics at once. ### Advanced Configuration The `options` prop accepts a JSON object with the following properties: ```javascript Basic Options theme={"dark"} { "disableDownloadDataNoFilters": false, "disableDownloadUnderlyingDataNoFilters": false, "isShowNoDataFoundScreen": false, "disableMetricCreation": false, "disableMetricUpdation": false, "disableMetricCardBorder": false, "disableMetricDeletion": false, "disableLayoutCustomization": false, "dashboardSpacing": { "verticalGap": 30, "horizontalGap": 30, "hide": false, }, "disableSaveLayout": false, "disableScheduleEmailReports": false, "disableManageMetrics": false, "disableMainLoader": false, "disableMetricLoader": false, "hideDashboardName": false, "allowedChartTypes": ["line", "bar", "stack", "row", "combo", "pie", "doughnut", "waterfall", "funnelV2", "gaugeV2", "singleValue", "table", "pivotV2", "rose", "horizontalStack", "treeMap", "progressBarV2"], "hideMetricCardShadow": false, "showDashboardActions": true, "disableUnderlyingData": false, "shouldFitFullScreen": false, "isModifyUrl": false, "exportMsgPosition": "bottom", "dashboardPadding": "16px", "ctaButtonCustomization": { "primary": { "styles": "background-color: #2563eb; color: #ffffff; border-radius: 8px;", "hoverStyles": "background-color: #1d4ed8;", "activeStyles": "background-color: #1e40af;", "disabledStyles": "opacity: 0.5;" }, "secondary": { "styles": "background-color: #f1f5f9; color: #0f172a;" }, "tertiary": { "styles": "color: #2563eb;" } }, "showAllChartSettings": false, "renameBoard": "workspace", "enableDashboardMinimap": true } ``` ```javascript Chart Customization theme={"dark"} { "chartColors": ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"], "chartPaletteOptions": [ { "name": "custom1", "colors": ["...9 colors"] }, { "name": "custom2", "colors": ["...9 colors"] }, { "name": "custom3", "colors": ["...9 colors"] } ], "hideDatePickerOptions": ["this month", "yesterday"], "chartAppearance": { "chartTooltip": { "labelStyle": { "size": 14, "family": "Inter", "weight": 400, "color": "#000000" }, "valueStyle": { "size": 14, "family": "Inter", "weight": 400, "color": "#000000" }, "tooltipHeader": { "size": 14, "family": "Inter", "weight": 400, "color": "#000000" } "tooltipCard": { "bgColor": "#FFFFFF", "borderColor": "#FFFFFF", "borderRadius": 14, "padding": 10, }, }, "chartLabel": { "position": "hidden", "radialChartposition": "outside" }, "chartMargin": { "marginTop": 15, "marginLeft": 15, "marginRight": 15, "marginBottom": 15 }, "chartLegend": { "show": true, "fixedPosition": "top-left", "enableVariablePosition": false, "top": 15, "left": 15, "disableLegendScrolling": true, "legendAppearance": "horizontal", "truncateLegend": 22, "legendShape": "circle", "fontSize": 14, "fontWeight": 400, "fontFamily": "Inter", "color": "#000000" }, "verticalAxis": { "hideAxisLines": false, "hideSplitLines": false, "hideAxisLabels": false, "hideAxisTicks": false, "axisName": "axisName", "axisNameOffset": 20, "axisLabelMargin": 0, "fontSize": 14, "fontFamily": "Inter", "fontWeight": 400, "color": "#000000", "axisColor": "#000000", "axisNameFontConfig": { "fontFamily": "Inter", "fontSize": 14, "fontWeight": 400 } }, "horizontalAxis": { "hideAxisLines": false, "hideSplitLines": false, "hideAxisLabels": false, "hideAxisTicks": false, "axisName": "axisName", "axisNameOffset": 20, "axisLabelMargin": 0, "fontSize": 14, "fontFamily": "Inter", "fontWeight": 400, "color": "#000000", "axisColor": "#000000", "axisNameFontConfig": { "fontFamily": "Inter", "fontSize": 14, "fontWeight": 400 } } } } ``` Prevents downloading data when no filters are applied. Prevents downloading underlying data when no filters are applied. Shows a custom screen when no data is available. Disables the ability to create new metrics. Disables the ability to update existing metrics. Controls visibility of dashboard actions like create metric, customize layout. Renames the dashboard "Board" view-filter UI text (tab label, dropdown label, Add/Save CTA, and modal copy). If the value contains multiple words, only the first word is used. Enables the dashboard minimap and progress header in an embedded dashboard. The minimap is disabled by default in embeds; set this option to `true` inside the dashboard `options` object to enable it. This option applies to `dbn-dashboard` and does not change the UI Theming setting used by dashboards in the app. Makes full screen modal take up space equivalent to the dashboard component. When enabled, the component appends state information (such as the active metric) to the browser URL. Useful for deep-linking into a specific view. Controls the position of the "Exporting Dashboard" prompt that appears while a dashboard export is in progress. Set to `"hidden"` to suppress the message entirely. Options: `"bottom"` | `"bottom-left"` | `"bottom-right"` | `"center"` | `"top"` | `"top-left"` | `"top-right"` | `"hidden"` Controls the horizontal and vertical spacing between the metrics on the grid. Optional `hide` field hides the **Adjust Spacing** button from **Customize Layout**. ```javascript theme={"dark"} "dashboardSpacing": { "verticalGap": 30, "horizontalGap": 30, "hide": true, } ``` * When omitted, default layout spacing applies. * Applying either of the **verticalGap** or **horizontalGap** sets the other to a default of **10**, unless configured here. * This controls the spacing **between** metrics on the grid. For setting outer wrapper padding around the embedded dashboard use **`dashboardPadding`** inside the same `options` object. Optional CSS value for the main dashboard embed wrapper padding. Uses the same rules as the standard CSS `padding` shorthand (for example `"16px"`, `"12px 24px"`, `"8px 12px 16px"`). Applied as an inline style on the embed dashboard container. * When omitted, default layout padding from stylesheets applies. * This controls outer wrapper padding around the embedded dashboard. For spacing **between** metrics on the grid, use **`dashboardSpacing`** inside the same `options` object. Optional styling overrides for dashboard CTA buttons (primary, secondary, and tertiary variants). Injected styles target `.cta-primary`, `.cta-secondary`, and `.cta-tertiary`, so they apply anywhere those classes are used in the embedded experience (for example dashboard action buttons and full-screen metric controls). Each variant supports optional string fields — pass fragments of CSS declarations (semicolon-separated), similar to inline style text: * **`styles`** — base state * **`hoverStyles`** — `:hover:enabled` * **`activeStyles`** — `:active` * **`disabledStyles`** — `:disabled` ```typescript theme={"dark"} { primary?: { styles?: string; hoverStyles?: string; activeStyles?: string; disabledStyles?: string; }; secondary?: { /* same fields */ }; tertiary?: { /* same fields */ }; } ``` * **`background-color`** and **`color`** rules you provide are enforced with `!important` so they win over theme defaults. * If **`styles`** includes a **`height:`** declaration, a companion height helper class may be generated for layout alignment (implementation detail). * This is separate from **`admin-theme-options.dashboard.ctaColor`** / **`ctaTextColor`**, which set broad theme defaults; **`ctaButtonCustomization`** targets granular CSS per variant and state. Array of color strings for chart styling. Defaults to Recharts default colors. ```javascript theme={"dark"} ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FECA57"] ``` Array of custom color palette options that users can select from. Each palette should contain a name and an array of 9 colors for comprehensive chart coverage. ```javascript theme={"dark"} [ { name: "Ocean Blues", colors: ["#003f5c", "#2f4b7c", "#665191", "#a05195", "#d45087", "#f95d6a", "#ff7c43", "#ffa600", "#ffd700"] }, { name: "Forest Greens", colors: ["#004d00", "#006600", "#008000", "#009900", "#00b300", "#00cc00", "#00e600", "#00ff00", "#66ff66"] }, { name: "Sunset Warmth", colors: ["#8b0000", "#a52a2a", "#cd5c5c", "#dc143c", "#ff6347", "#ff7f50", "#ffa500", "#ffd700", "#ffffe0"] } ] ``` Detailed chart styling configuration for tooltips, labels, margins, legends, and axes. ```jsx theme={"dark"} { chartTooltip?: { labelStyle?: { size?: number, family?: string, weight?: number, color?: string, }, valueStyle?: { size?: number, family?: string, weight?: number, color?: string, }, tooltipHeader?: { size?: number, family?: string, weight?: number, color?: string, }, tooltipCard?: { bgColor?: string, borderColor?: string, borderRadius?: number, padding?: number, }, }, chartLabel?: { position?: "hidden" | "top" | "left" | "right" | "bottom" | "inside", radialChartposition?: "outside" | "inside", }, chartMargin?: { marginTop?: number, marginLeft?: number, marginRight?: number, marginBottom?: number, }, chartLegend?: { show?: boolean, fixedPosition?: "top-left" | "top-center" | "top-right" | "left-center" | "right-center" | "bottom-left" | "bottom-center" | "bottom-right", enableVariablePosition?: boolean, top?: number, left?: number, disableLegendScrolling?: boolean, legendAppearance?: "horizontal" | "vertical", truncateLegend?: number, legendShape?: "circle" | "rect" | "roundRect" | "triangle" | "diamond" | "arrow" | "none", fontSize?: number, fontWeight?: number, fontFamily?: string, color?: string, }, verticalAxis?: { hideAxisLines?: boolean, hideSplitLines?: boolean, hideAxisLabels?: boolean, hideAxisTicks?: boolean, axisName?: string, axisNameOffset?: number, axisLabelMargin?: number, fontSize?: number, fontFamily?: string, fontWeight?: number, color?: string, axisColor?: string, axisNameFontConfig?: { fontFamily?: string, fontSize?: number, fontWeight?: number, }, }, horizontalAxis?: { hideAxisLines?: boolean, hideSplitLines?: boolean, hideAxisLabels?: boolean, hideAxisTicks?: boolean, axisName?: string, axisNameOffset?: number, axisLabelMargin?: number, fontSize?: number, fontFamily?: string, fontWeight?: number, color?: string, axisColor?: string, axisNameFontConfig?: { fontFamily?: string, fontSize?: number, fontWeight?: number, }, }, } ``` Configure global filters for the dashboard: ```javascript String Filter theme={"dark"} { "Filter name for a string datatype": { "options": [ { "value": "James Smith", "label": "James" }, { "value": "Olivia Johnson", "label": "Olivia" }, { "value": "Emma Brown", "label": "Emma" } ], "defaultOption": "James Smith" } } ``` ```javascript Number Filter theme={"dark"} { "Filter name for a number datatype": { "defaultOption": {"min": 100, "max": 900} } } ``` ```javascript Date Filter theme={"dark"} { "Filter name for a date datatype": { "defaultOption": {"startDate": "2024-01-01", "endDate": "2024-12-31"}, "datePresetOptions": [ { "type": "this", "interval": 1, "timeGrain": "month", "label": "this month", "startDate": "2024-01-01", "endDate": "2024-01-31" } ] } } ``` Custom theme configuration for component styling. ```javascript theme={"dark"} { "button": { "primaryText": "white", "primary": "#007bff", "secondaryText": "black", "secondary": "white" }, "checkbox": { "checked": "#007bff", "unChecked": "#6c757d" }, "switch": { "enabled": "#28a745", "disabled": "#6c757d" }, "drillBreadCrumbs": { "fontFamily": "Inter", "fontColor": "black", "activeColor": "#007bff" }, "multiSelectFilterDropdown": { "badgeColor": "#007bff", "badgeTextColor": "white" } } ``` Name of a predefined theme from app settings UI theming. Advanced UI theming configuration for the dashboard. Controls fonts, backgrounds, CTA colors, card styling, and chart palettes. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { "general": { "name": "My Theme", "fontFamily": "Inter", "datePickerFormat": "DD-MM-YYYY" }, "dashboard": { "backgroundColor": "#FFFFFF", "ctaColor": "#007bff", "ctaTextColor": "#FFFFFF", "selectBoxSize": "medium", "selectBoxVariant": "floating", "selectBoxBorderRadius": "8px", "selectBoxTextColor": "#333333", "metricCardColor": "#FFFFFF" }, "cardTitle": { "fontSize": "16px", "fontWeight": "600", "color": "#000000", "elementColor": "#1e293b" }, "cardDescription": { "fontSize": "12px", "fontWeight": "400", "color": "#666666", "elementColor": "#64748b" }, "chart": { "palettes": [ { "name": "Custom Palette", "colors": ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FECA57"] } ], "paletteOptions": ["Custom Palette"], "selected": "Custom Palette", "fontFamily": "Roboto", "fontColor": "#333333", "letterSpacing": "0.5px", "tooltip": { "header": { "fontFamily": "Roboto", "fontSize": "14px", "fontWeight": "bold", "fontColor": "#000000" }, "label": { "fontFamily": "Roboto", "fontSize": "12px", "fontWeight": "normal", "fontColor": "#333333" }, "value": { "fontFamily": "Roboto", "fontSize": "12px", "fontWeight": "bold", "fontColor": "#000000" } } }, "cardCustomization": { "padding": "16px", "borderRadius": "8px", "shadow": "0 2px 8px rgba(0,0,0,0.1)", "disableShadowOnHover": false, "disableStroke": false, "metricStrokeColor": "#E0E0E0" } } ``` Name of the theme. Global font family applied to the dashboard. Date format string for date pickers (e.g. `"DD-MM-YYYY"`, `"MM-DD-YYYY"`, `"YYYY-MM-DD"`). Background color of the dashboard container. Primary call-to-action button color. Text color for call-to-action buttons. Size of filter select boxes. Options: `"small"` | `"medium"` | `"large"` Style variant for filter select boxes. Options: `"floating"` | `"static"` Border radius for filter select boxes (e.g. `"8px"`). Text color for filter select boxes. Background color of individual metric cards. Font size of metric card titles (e.g. `"16px"`). Font weight of metric card titles (e.g. `"600"`). Text color of standard metric card titles (`.dbn-metric-card-title`). Text color for **element** metric titles — titles rendered in the element layout (`.dbn-metric-element-title`). Use when element metrics should differ from `cardTitle.color`. Applied with `!important` when set. * **`color`** styles the default card chrome title. * **`elementColor`** styles only element-mode titles. Omit either field to fall back to product defaults for that surface. Font size of metric card descriptions. Font weight of metric card descriptions. Text color of standard metric card descriptions (`.dbn-metric-card-description`). Text color for **element** metric descriptions (`.dbn-metric-element-description`). Separate from `cardDescription.color`; applied with `!important` when set. Array of custom chart color palettes. Each palette has a `name` and an array of `colors`. Array of palette name strings available for selection. Name of the currently selected palette. Font family applied to chart axis labels, legend text, and chart titles (e.g. `"Roboto"`). Default text color for chart axis labels, legend text, and chart titles (e.g. `"#333333"`). Letter spacing applied to chart text elements (e.g. `"0.5px"`). Global tooltip font configuration with nested `header`, `label`, and `value` objects. Each accepts `fontFamily`, `fontSize`, `fontWeight`, and `fontColor`. **Known limitation:** The chart-level font fields (`chart.fontFamily`, `chart.fontColor`, `chart.letterSpacing`, `chart.tooltip`) are currently only applied from **saved admin themes** (configured via the Databrain admin UI or the `theme-name` prop). Passing them directly via the `admin-theme-options` prop will **not** affect chart rendering. Other `admin-theme-options` fields (dashboard colors, card styling, palettes, `datePickerFormat`) work correctly via the prop. Inner padding of metric cards (e.g. `"16px"`). Border radius of metric cards (e.g. `"8px"`). Box shadow of metric cards (e.g. `"0 2px 8px rgba(0,0,0,0.1)"`). Disables the shadow effect when hovering over metric cards. Disables the border stroke around metric cards. Border stroke color for metric cards when stroke is enabled (e.g. `"#E0E0E0"`). ### Additional Dashboard Properties Controls the appearance of metric long-description tooltips. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { "width": "300px", "fontColor": "#333333" } ``` Restricts which columns are available to end users for each metric. Each entry targets a specific metric. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} [ { "metricId": "metric-1", "isEnabled": true, "dimensions": ["region", "category"], "measures": ["revenue", "profit"] } ] ``` ### Per-Metric Chart Settings Per-metric chart settings that allow you to set default values and control whether end users can edit each setting. Must be passed as `JSON.stringify(...)`. Refer to the [Custom Chart Settings Reference](#custom-chart-settings-reference) section below for the complete schema. ```javascript Example theme={"dark"} { labelSettings: { XAxisStyle: { size: { defaultValue: 12, canEdit: true } } }, legendSettings: { show: { defaultValue: true, canEdit: false } } } ``` ```html Component Usage theme={"dark"} ``` *** ### Internationalization Language code for component localization (e.g., "fr", "es", "de"). Custom translation dictionary for component text. ```javascript theme={"dark"} { "total sales": { "en": "total sales", "fr": "ventes totales", "es": "ventas totales", "de": "Gesamtumsatz" } } ``` Calendar system to use. Options: `default` | `ind` ### Event Handling Name of a global function to handle server events. Define the function in the global scope. ```javascript Function Definition theme={"dark"} // Define globally accessible function window.myServerEventHandler = (event) => { console.log('Server event:', event); // Handle the event }; ``` ```html Component Usage theme={"dark"} ``` ### Custom Chart Click Action Name of a global function to call when a user clicks on a chart data point. Define the function in the global scope. ```javascript Function Definition theme={"dark"} // Define globally accessible function window.myChartClickHandler = (data) => { console.log('Chart clicked:', data); // Handle the click data }; ``` ```html Component Usage theme={"dark"} ``` The shape of the `data` parameter depends on the chart type: | Chart Type | Data Shape | Example | | ---------------- | -------------------------------------------------- | ---------------------------------------------------- | | Table | `{ columnName: value, ... }` | `{ "product name": "Product A1", "price": 4.444 }` | | Tree Map, Sankey | `{ name: xVal, value: yVal }` | `{ name: "Category A", value: 1200 }` | | All other charts | `{ name: xVal, value: yVal, columnName: colName }` | `{ name: "Jan", value: 500, columnName: "revenue" }` | When Pass Complete Data is not enabled, the clicked value is directly passed instead of the data object. ### Custom Messages Custom messages for various component states. ```javascript theme={"dark"} { "tokenExpiry": "Your session has expired. Please refresh the page.", "tokenAbsent": "Authentication token is missing. Please log in again." } ``` *** ## Custom Chart Settings Reference The `custom-chart-settings` prop allows you to configure default values and control end-user editability for individual chart settings on each metric card. Every field follows the shape `{ defaultValue: , canEdit: true | false }`. `custom-chart-settings` defaults are only applied when a metric is **first created**. They do not override settings already saved on existing metrics. See [Understanding the Configuration Layers](#understanding-the-configuration-layers). ### Field Name Mapping The `chart-appearance` prop (Priority 1) and `custom-chart-settings` prop (Priority 3) use **different field names** for overlapping concepts. Use this table to find the equivalent field when switching between layers. | Concept | `chart-appearance` field | `custom-chart-settings` field | | ------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------- | | Legend visibility | `chartLegend.show` | `legendSettings.show` | | Legend orientation | `chartLegend.legendAppearance` (`"horizontal"` / `"vertical"`) | `legendSettings.position` (`"horizontal"` / `"vertical"`) | | Legend position | `chartLegend.fixedPosition` (e.g. `"bottom-center"`) | `legendSettings.fixedPosition` | | Legend shape | `chartLegend.legendShape` | `legendSettings.legendShape` | | Legend scrolling | `chartLegend.disableLegendScrolling` | `legendSettings.disableScroll` | | Legend truncation | `chartLegend.truncateLegend` | `legendSettings.truncateLegendValue` | | Legend font | `chartLegend.fontSize` / `fontWeight` / `fontFamily` / `color` | `legendSettings.fontSize` / `fontWeight` / `fontFamily` / `color` | | Tooltip label font | `chartTooltip.labelStyle.{size,family,weight,color}` | `tooltipSettings.labelStyle.{size,family,weight,color}` | | Tooltip value font | `chartTooltip.valueStyle.{size,family,weight,color}` | `tooltipSettings.valueStyle.{size,family,weight,color}` | | Tooltip header font | `chartTooltip.tooltipHeader.{size,family,weight,color}` | `tooltipSettings.tooltipHeader.{size,family,weight,color}` | | Label position | `chartLabel.position` | `labelSettings.position` | | Margins | `chartMargin.{marginTop,marginLeft,marginRight,marginBottom}` | `margins.{marginTop,marginLeft,marginRight,marginBottom}` | | X-axis label font | `horizontalAxis.{fontSize,fontFamily,fontWeight,color}` | `labelSettings.XAxisStyle.{size,family,weight,color}` | | Y-axis label font | `verticalAxis.{fontSize,fontFamily,fontWeight,color}` | `labelSettings.YAxisStyle.{size,family,weight,color}` | | Hide axis lines | `verticalAxis.hideAxisLines` / `horizontalAxis.hideAxisLines` | `customSettings.hideXAxisLines` / `customSettings.hideYAxisLines` | | Hide split lines | `verticalAxis.hideSplitLines` / `horizontalAxis.hideSplitLines` | `customSettings.hideXSplitLines` / `customSettings.hideYSplitLines` | | Axis label margin | `verticalAxis.axisLabelMargin` / `horizontalAxis.axisLabelMargin` | `labelSettings.XAxisStyle.axisMargin` / `labelSettings.YAxisStyle.axisMargin` | ```javascript theme={"dark"} margins: { marginTop: { defaultValue: 20, canEdit: true | false }, marginBottom: { defaultValue: 5, canEdit: true | false }, marginLeft: { defaultValue: 5, canEdit: true | false }, marginRight: { defaultValue: 5, canEdit: true | false }, } ``` ```javascript theme={"dark"} chartColors: { defaultValue: ['#FF0000', '#FF7F00', '#FFFF00', '#00FF00', '#0000FF', '#4B0082', '#8B00FF', '#FF1493', '#00FFFF'], canEdit: true | false } ``` ```javascript theme={"dark"} legendSettings: { show: { defaultValue: true | false, canEdit: true | false }, top: { defaultValue: 0, canEdit: true | false }, left: { defaultValue: 0, canEdit: true | false }, position: { defaultValue: 'horizontal' | 'vertical', canEdit: true | false }, truncateLegendValue: { defaultValue: 20, canEdit: true | false }, legendShape: { defaultValue: 'roundRect' | 'diamond' | 'triangle' | 'circle' | 'arrow', canEdit: true | false }, customise: { defaultValue: true | false, canEdit: true | false }, fixedPosition: { defaultValue: 'bottom-center', canEdit: true | false }, disableScroll: { defaultValue: true | false, canEdit: true | false }, fontSize: { defaultValue: 12, canEdit: true | false }, fontFamily: { defaultValue: 'Inter', canEdit: true | false }, fontWeight: { defaultValue: 400, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, } ``` ```javascript theme={"dark"} labelSettings: { position: { defaultValue: 'left' | 'right' | 'top' | 'bottom' | 'inside' | 'outside' | 'hidden', canEdit: true | false }, truncateLabel: { defaultValue: true | false, canEdit: true | false }, truncateLabelValue: { defaultValue: 10, canEdit: true | false }, showLabelLine: { defaultValue: true | false, canEdit: true | false }, isEnableValueSummation: { defaultValue: false, canEdit: true | false }, showDimension: { defaultValue: true | false, canEdit: true | false }, isDynamicPosition: { defaultValue: true | false, canEdit: true | false }, showActualValue: { defaultValue: true | false, canEdit: true | false }, XAxisStyle: { size: { defaultValue: 12, canEdit: true | false }, family: { defaultValue: 'Inter', canEdit: true | false }, weight: { defaultValue: 400, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, axisName: { defaultValue: '', canEdit: true | false }, axisPadding: { defaultValue: 0, canEdit: true | false }, axisMargin: { defaultValue: 0, canEdit: true | false }, axisNameFontConfig: { fontFamily: { defaultValue: 'Inter', canEdit: true | false }, fontSize: { defaultValue: 12, canEdit: true | false }, fontWeight: { defaultValue: 400, canEdit: true | false }, }, }, YAxisStyle: { size: { defaultValue: 12, canEdit: true | false }, family: { defaultValue: 'Inter', canEdit: true | false }, weight: { defaultValue: 400, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, axisName: { defaultValue: '', canEdit: true | false }, axisPadding: { defaultValue: 0, canEdit: true | false }, axisMargin: { defaultValue: 0, canEdit: true | false }, axisNameFontConfig: { fontFamily: { defaultValue: 'Inter', canEdit: true | false }, fontSize: { defaultValue: 12, canEdit: true | false }, fontWeight: { defaultValue: 400, canEdit: true | false }, }, }, } ``` ```javascript theme={"dark"} tooltipSettings: { labelStyle: { size: { defaultValue: 12, canEdit: true | false }, family: { defaultValue: 'Inter', canEdit: true | false }, weight: { defaultValue: 400, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, }, valueStyle: { size: { defaultValue: 12, canEdit: true | false }, family: { defaultValue: 'Inter', canEdit: true | false }, weight: { defaultValue: 400, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, }, tooltipHeader: { size: { defaultValue: 14, canEdit: true | false }, family: { defaultValue: 'Inter', canEdit: true | false }, weight: { defaultValue: 600, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, }, tooltipCard: { bgColor: {defaultValue: '#FFFFFF', canEdit: true | false }, borderColor: {defaultValue: '#FFFFFF', canEdit: true | false }, } } ``` ```javascript theme={"dark"} axisSettings: { axis: { defaultValue: 'left' | 'right', canEdit: true | false }, } ``` ```javascript theme={"dark"} customSettings: { isEnableCustomLimits: { defaultValue: true | false, canEdit: true | false }, isEnableDynamicLimits: { defaultValue: true | false, canEdit: true | false }, isEnableLogScale: { defaultValue: true | false, canEdit: true | false }, customUpperLimit: { defaultValue: 0, canEdit: true | false }, customLowerLimit: { defaultValue: 0, canEdit: true | false }, hideXSplitLines: { defaultValue: true | false, canEdit: true | false }, hideYSplitLines: { defaultValue: true | false, canEdit: true | false }, hideXAxisLines: { defaultValue: true | false, canEdit: true | false }, hideYAxisLines: { defaultValue: true | false, canEdit: true | false }, hideYAxisTicks: { defaultValue: true | false, canEdit: true | false }, hideXAxisTicks: { defaultValue: true | false, canEdit: true | false }, hideXAxisLabels: { defaultValue: true | false, canEdit: true | false }, hideYAxisLabels: { defaultValue: true | false, canEdit: true | false }, } ``` ```javascript theme={"dark"} customSettings: { numberFormatter: { defaultValue: '', canEdit: true | false }, isEnableLabelFormatting: { defaultValue: true | false, canEdit: true | false }, isEnableTimezoneFormatting: { defaultValue: true | false, canEdit: true | false }, isEnableBgColor: { defaultValue: true | false, canEdit: true | false }, timeFormatter: { defaultValue: '', canEdit: true | false }, labelPrefix: { defaultValue: '', canEdit: true | false }, labelSuffix: { defaultValue: '', canEdit: true | false }, isEnableLabelTooltip: { defaultValue: true | false, canEdit: true | false }, YaxislabelFormatters: { defaultValue: [{ upperLimit: 1000, lowerLimit: 0, label: 'Low', color: '#00FF00' }], canEdit: true | false, }, } ``` ```javascript theme={"dark"} customSettings: { enableTitleDesc: { defaultValue: true | false, canEdit: true | false }, chartTitle: { defaultValue: '', canEdit: true | false }, chartDesc: { defaultValue: '', canEdit: true | false }, titlePosition: { defaultValue: 'top', canEdit: true | false }, subHeaderShow: { defaultValue: true | false, canEdit: true | false }, displayText: { defaultValue: '', canEdit: true | false }, subHeaderAlignment: { defaultValue: 'center', canEdit: true | false }, } ``` ```javascript theme={"dark"} customSettings: { singleValConditionalFormatter: { defaultValue: [{ type: 'range', min: 0, max: 100, color: '#00FF00' }], canEdit: true | false, }, } ``` ```javascript theme={"dark"} customSettings: { barWidth: { defaultValue: 20, canEdit: true | false }, barRadius: { defaultValue: [0, 0, 0, 0], canEdit: true | false }, cumulativeBar: { defaultValue: true | false, canEdit: true | false }, showFullStacked: { defaultValue: true | false, canEdit: true | false }, } ``` ```javascript theme={"dark"} customSettings: { comboAxisSettings: { defaultValue: [{ axis: 'left', measures: ['revenue'], chartTypes: [{ axis: 'left', type: 'bar' }] }], canEdit: true | false, }, } ``` ```javascript theme={"dark"} customSettings: { isEnableMeasureMode: { defaultValue: true | false, canEdit: true | false }, chartZoom: { isZoomEnabled: { defaultValue: true | false, canEdit: true | false }, zoomAxis: { defaultValue: 'x', canEdit: true | false }, }, } ``` ```javascript theme={"dark"} customSettings: { markers: { isEnableMax: { defaultValue: true | false, canEdit: true | false }, isEnableMin: { defaultValue: true | false, canEdit: true | false }, isEnableAvg: { defaultValue: true | false, canEdit: true | false }, maxColor: { defaultValue: '#008000', canEdit: true | false }, minColor: { defaultValue: '#FF0000', canEdit: true | false }, }, } ``` ```javascript theme={"dark"} customSettings: { linearGaugeV2: { upperLimit: { isEnable: { defaultValue: true | false, canEdit: true | false }, limit: { defaultValue: 100, canEdit: true | false }, color: { defaultValue: '#000000', canEdit: true | false }, message: { defaultValue: '', canEdit: true | false }, messageSize: { defaultValue: 12, canEdit: true | false }, }, lowerLimit: { isEnable: { defaultValue: true | false, canEdit: true | false }, limit: { defaultValue: 0, canEdit: true | false }, message: { defaultValue: '', canEdit: true | false }, messageSize: { defaultValue: 12, canEdit: true | false }, }, }, } ``` ```javascript theme={"dark"} tableSettings: { conditionalFormatting: { defaultValue: [{ columnName: 'status', rules: [{ operator: '=', value: 'Active', styles: { backgroundColor: '#00FF00', color: '#000000', isApplyBgColor: true } }] }], canEdit: true | false, }, } ``` ```javascript theme={"dark"} tableSettings: { isEnableNumberFormatting: { defaultValue: true | false, canEdit: true | false }, tableNumberFormatter: { defaultValue: [{ columns: ['revenue'], formatter: '#,##0.00', suffix: 'K', prefix: '$' }], canEdit: true, }, isEnableTimezoneFormatting: { defaultValue: true | false, canEdit: true | false }, timeFormatter: { defaultValue: 'original' | 'yyyy-MM-dd' | 'yyyy/MM/dd' | 'dd-MM-yyyy' | 'dd/MM/yyyy' | 'dd MMM yyyy' | 'dd MMMM yyyy' | 'yyyy MMMM dd' | 'MMMM dd, yyyy' | 'yyyy-MM-dd, h:mm:ss a' | 'h:mm a', canEdit: true | false }, } ``` *** ## Metric Component (`dbn-metric`) The metric component displays a single metric with customizable appearance and interactions. ### Required Properties Guest token for authentication. Unique identifier for the metric to display. ### Display Properties Width of the metric component in pixels. Height of the metric component in pixels. Display variant. Options: `card` | `fullscreen` Chart rendering method. Options: `svg` | `canvas` ### Behavior Options Enables CSV download in metric card actions. Enables email CSV option in metric card actions. Disables PNG download in full screen mode. Disables the full screen button. Hides table preview in full screen view. Hides chart settings in full screen view. Disables access to underlying data. Removes border from metric card. Removes shadow from metric card. Hides the metric card title. Enables fullscreen mode when the metric title is clicked. Controls which options icon to display. Options: `kebab-menu-vertical` | `download` Prevents downloading underlying data when no filters are applied. Prevents downloading data when no filters are applied. ### Filter Configuration Allows multiple metric filters. Position of metric filters. Options: `inside` | `outside` Configuration for metric-specific filters. ```javascript theme={"dark"} { "Filter name for a string datatype": { "options": [ { "value": "James Smith", "label": "James" }, { "value": "Olivia Johnson", "label": "Olivia" } ], "defaultOption": "James Smith" }, "Filter name for a number datatype": { "options": [ { "value": 1, "label": "Option 1" }, { "value": 2, "label": "Option 2" } ], "defaultOption": 1 }, "Filter name for a date datatype": { "options": [ { "range": "Last", "time": "Year", "name": "Last 10 Years", "count": 10, "fromDate": "2023-01-01", "toDate": "2023-12-31" } ], "defaultOption": "Last 10 Years" } } ``` ### Chart Appearance Detailed chart styling configuration. ```javascript theme={"dark"} { chartTooltip?: { labelStyle?: { size?: number; family?: string; weight?: number; color?: string; }; valueStyle?: { size?: number; family?: string; weight?: number; color?: string; }; tooltipHeader?: { size?: number; family?: string; weight?: number; color?: string; }; }; chartLabel?: { position?: 'hidden' | 'top' | 'left' | 'right' | 'bottom' | 'inside'; radialChartposition?: 'outside' | 'inside'; }; chartMargin?: { marginTop?: number; marginLeft?: number; marginRight?: number; marginBottom?: number; }; chartLegend?: { show?: boolean; fixedPosition?: | 'top-left' | 'top-center' | 'top-right' | 'left-center' | 'right-center' | 'bottom-left' | 'bottom-center' | 'bottom-right'; enableVariablePosition?: boolean; top?: number; left?: number; disableLegendScrolling?: boolean; legendAppearance?: 'horizontal' | 'vertical'; truncateLegend?: number; legendShape?: | 'circle' | 'rect' | 'roundRect' | 'triangle' | 'diamond' | 'arrow' | 'none'; fontSize?: number; fontWeight?: number; fontFamily?: string; color?: string; }; verticalAxis?: { hideAxisLines?: boolean; hideSplitLines?: boolean; hideAxisLabels?: boolean; hideAxisTicks?: boolean; axisName?: string; axisNameOffset?: number; axisLabelMargin?: number; fontSize?: number; fontFamily?: string; fontWeight?: number; color?: string; axisColor?: string; axisNameFontConfig?: { fontFamily?: string; fontSize?: number; fontWeight?: number; }; }; horizontalAxis?: { hideAxisLines?: boolean; hideSplitLines?: boolean; hideAxisLabels?: boolean; hideAxisTicks?: boolean; axisName?: string; axisNameOffset?: number; axisLabelMargin?: number; fontSize?: number; fontFamily?: string; fontWeight?: number; color?: string; axisColor?: string; axisNameFontConfig?: { fontFamily?: string; fontSize?: number; fontWeight?: number; }; }; }; ``` Interactive appearance options for the metric. ```javascript theme={"dark"} { "appearanceOptionsPosition": "top-right", "dynamicBehaviour": { "isEnabled": true, "label": "Dynamic" }, "cumulativeBar": { "isEnabled": true, "label": "Cumulative" }, "stackedBars": { "isEnabled": true, "label": "Stacked" } } ``` ### Internationalization & Configuration Language code for component localization (e.g., `"fr"`, `"es"`, `"de"`). Custom translation dictionary for metric text. Must be passed as `JSON.stringify(...)`. See the dashboard [Internationalization](#internationalization) section for the full schema. Calendar system to use. Options: `default` | `ind` Name of a predefined theme from app settings UI theming. Custom messages for component states. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { "tokenExpiry": "Your session has expired. Please refresh the page.", "tokenAbsent": "Authentication token is missing. Please log in again." } ``` Pre-configured filter values for the metric. Must be passed as `JSON.stringify(...)`. See the dashboard [Global Filter Options](#global-filter-options) section for the full schema. Controls the appearance of metric long-description tooltips. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { "width": "300px", "fontColor": "#333333" } ``` Restricts which columns are available to end users for this metric. Must be passed as `JSON.stringify(...)`. ```javascript theme={"dark"} { "isEnabled": true, "dimensions": ["region", "category"], "measures": ["revenue", "profit"] } ``` ### Event Callbacks Name of global function to call when metric is minimized. ```javascript Function Definition theme={"dark"} window.handleMetricMinimize = (metricId) => { console.log('Metric minimized:', metricId); }; ``` ```html Component Usage theme={"dark"} ``` *** ## Common Properties These properties are available for both dashboard and metric components: ### Styling & Customization Inline CSS styles for the component. CSS class name for custom styling. Array of colors for chart elements. ```javascript Example Colors theme={"dark"} ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FECA57"] ``` ### No Data Handling SVG code as string to display when no data is available. SVG code as string to display when no data is found in dashboard. ### Date Picker Configuration Array of date picker option labels to hide. ```javascript Example theme={"dark"} ["this month", "yesterday", "last week"] ``` *** ## Usage Examples ```html theme={"dark"} ``` ```html theme={"dark"} ``` ```html theme={"dark"} ``` ```html theme={"dark"} ``` *** ## Frequently Asked Questions Web components don't automatically re-render when properties change. Here are several approaches: **Method 1: Force Re-render with Key** ```javascript theme={"dark"} const [componentKey, setComponentKey] = useState(0); const [token, setToken] = useState(initialToken); // When updating props const updateProps = (newToken) => { setToken(newToken); setComponentKey(prev => prev + 1); // Force re-render }; return ( ); ``` **Method 2: Loading State Approach** ```javascript theme={"dark"} const [isLoading, setIsLoading] = useState(false); const [token, setToken] = useState(initialToken); const updateToken = async (newToken) => { setIsLoading(true); // Brief delay to ensure component unmounts await new Promise(resolve => setTimeout(resolve, 100)); setToken(newToken); setIsLoading(false); }; return ( <> {isLoading ? (
Loading...
) : ( )} ); ```
This usually happens due to incorrect format or timing. Here are common solutions: **Ensure Proper Format:** ```javascript theme={"dark"} // ✅ Correct - Array of hex colors const chartColors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4"]; // ❌ Incorrect - Invalid color format const chartColors = ["red", "blue"]; // Use hex codes instead ``` **Use JSON.stringify for Complex Objects:** ```html theme={"dark"} ``` **Check CSS Specificity:** ```css theme={"dark"} /* Your custom colors might be overridden */ .your-dashboard-container { --chart-color-1: #FF6B6B !important; --chart-color-2: #4ECDC4 !important; } ``` **Set Up Custom Messages:** ```html theme={"dark"} ``` **Handle Server Events:** ```javascript theme={"dark"} // Define globally accessible function window.handleAuthError = (event) => { if (event.type === 'TOKEN_EXPIRED') { // Redirect to login or refresh token window.location.href = '/login'; } }; ``` **Automatic Token Refresh:** ```javascript theme={"dark"} const useTokenRefresh = () => { const [token, setToken] = useState(null); useEffect(() => { const refreshToken = async () => { try { const response = await fetch('/api/refresh-token'); const { token: newToken } = await response.json(); setToken(newToken); } catch (error) { console.error('Token refresh failed:', error); } }; // Refresh token every 50 minutes (assuming 1-hour expiry) const interval = setInterval(refreshToken, 50 * 60 * 1000); refreshToken(); // Initial call return () => clearInterval(interval); }, []); return token; }; ``` **Hide Specific Date Picker Options:** ```html theme={"dark"} ``` **Custom Filter Styling:** ```html theme={"dark"} ``` **Global Filter Configuration:** ```javascript theme={"dark"} const globalFilters = { "Region": { options: [ { value: "north", label: "North America" }, { value: "europe", label: "Europe" }, { value: "asia", label: "Asia Pacific" } ], defaultOption: "north" }, "Date Range": { defaultOption: { startDate: "2024-01-01", endDate: "2024-12-31" }, datePresetOptions: [ { type: "last", interval: 30, timeGrain: "day", label: "Last 30 Days" } ] } }; ``` **Common Causes & Solutions:** 1. **Invalid Token:** ```javascript theme={"dark"} // Check token validity const validateToken = async (token) => { try { const response = await fetch('/api/validate-token', { headers: { Authorization: `Bearer ${token}` } }); return response.ok; } catch (error) { console.error('Token validation failed:', error); return false; } }; ``` 2. **Incorrect Dashboard ID:** ```javascript theme={"dark"} // Verify dashboard exists const checkDashboard = async (dashboardId) => { try { const response = await fetch(`/api/dashboards/${dashboardId}`); return response.ok; } catch (error) { console.error('Dashboard check failed:', error); return false; } }; ``` 3. **Missing Import:** ```javascript theme={"dark"} // Ensure web components are imported import '@databrainhq/plugin/web'; // For TypeScript, add declarations declare global { namespace JSX { interface IntrinsicElements { 'dbn-dashboard': any; 'dbn-metric': any; } } } ``` 4. **Network/CORS Issues:** ```javascript theme={"dark"} // Check browser console for CORS errors // Ensure your backend allows requests from your domain ``` **Client-Side Implementation:** ```javascript theme={"dark"} const DashboardWithTenancy = ({ userId, tenantId }) => { const [token, setToken] = useState(null); useEffect(() => { const fetchTenantToken = async () => { const response = await fetch('/api/guest-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: userId, tenantId: tenantId, dataAppName: 'your-app-name' }) }); const { token } = await response.json(); setToken(token); }; fetchTenantToken(); }, [userId, tenantId]); if (!token) return
Loading...
; return ( ); }; ``` **Backend Token Generation:** ```javascript theme={"dark"} // Node.js example app.post('/api/guest-token', async (req, res) => { const { clientId, tenantId, dataAppName } = req.body; try { const response = await fetch('https://api.usedatabrain.com/api/v2/guest-token/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.DATABRAIN_API_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: `${tenantId}_${clientId}`, // Prefix with tenant dataAppName: dataAppName }) }); const data = await response.json(); res.json({ token: data.token }); } catch (error) { res.status(500).json({ error: 'Token generation failed' }); } }); ```
**Enable Canvas Rendering:** ```html theme={"dark"} ``` **Disable Heavy Features:** ```html theme={"dark"} ``` **Lazy Loading Implementation:** ```javascript theme={"dark"} const LazyDashboard = ({ dashboardId }) => { const [isVisible, setIsVisible] = useState(false); const ref = useRef(); useEffect(() => { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setIsVisible(true); observer.disconnect(); } }, { threshold: 0.1 } ); if (ref.current) observer.observe(ref.current); return () => observer.disconnect(); }, []); return (
{isVisible ? ( ) : (
Loading dashboard...
)}
); }; ```
**Responsive Width/Height:** ```javascript theme={"dark"} const ResponsiveMetric = () => { const [dimensions, setDimensions] = useState({ width: 500, height: 300 }); useEffect(() => { const handleResize = () => { const container = document.getElementById('metric-container'); if (container) { setDimensions({ width: container.offsetWidth, height: Math.min(container.offsetWidth * 0.6, 400) }); } }; window.addEventListener('resize', handleResize); handleResize(); // Initial call return () => window.removeEventListener('resize', handleResize); }, []); return (
); }; ``` **CSS Media Queries:** ```css theme={"dark"} .dashboard-container { width: 100%; max-width: 1200px; margin: 0 auto; } @media (max-width: 768px) { .dashboard-container { padding: 10px; } dbn-dashboard { --metric-card-padding: 8px; --font-size-small: 12px; } } @media (max-width: 480px) { dbn-dashboard { --chart-height: 200px; --hide-chart-legend: true; } } ``` **Mobile-Specific Options:** ```javascript theme={"dark"} const isMobile = window.innerWidth < 768; const mobileOptions = { hideMetricCardShadow: true, shouldFitFullScreen: true, chartAppearance: { chartLegend: { show: false }, chartMargin: { marginTop: 5, marginLeft: 5, marginRight: 5, marginBottom: 5 } } }; ```
**Global Error Handler:** ```javascript theme={"dark"} window.databrainErrorHandler = (error) => { // Log to your analytics service analytics.track('Databrain Error', { error: error.message, component: error.component, timestamp: new Date().toISOString() }); // Show user-friendly message if (error.type === 'NETWORK_ERROR') { showToast('Connection issue. Please check your internet connection.'); } else if (error.type === 'AUTH_ERROR') { redirectToLogin(); } else { showToast('Something went wrong. Please try again.'); } }; ``` **Component-Level Error Boundaries:** ```javascript theme={"dark"} class DashboardErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, errorInfo) { console.error('Dashboard Error:', error, errorInfo); // Log to error reporting service } render() { if (this.state.hasError) { return (

Dashboard temporarily unavailable

); } return this.props.children; } } // Usage ```
**Advanced Tooltip Customization:** ```javascript theme={"dark"} const tooltipConfig = { chartTooltip: { labelStyle: { size: 16, family: "Arial, sans-serif", weight: 600, color: "#2c3e50" }, valueStyle: { size: 14, family: "Arial, sans-serif", weight: 400, color: "#34495e" } } }; ``` **Legend Positioning:** ```javascript theme={"dark"} const legendConfig = { chartLegend: { show: true, fixedPosition: "bottom-center", // or use enableVariablePosition enableVariablePosition: false, legendAppearance: "horizontal", truncateLegend: 30, legendShape: "roundRect", fontSize: 12, fontWeight: 500, fontFamily: "Inter, sans-serif", color: "#2c3e50", disableLegendScrolling: false } }; ``` **Complete Chart Appearance:** ```html theme={"dark"} ```
*** ## Migration & Updates When updating from older versions, note that some property names may have changed. Always refer to this reference for the latest property names and structures. For dynamic property updates, web components don't automatically re-render. Consider using a loading state and temporarily hiding/showing the component when updating properties. ## Troubleshooting Quick Reference * ✅ Check if `@databrainhq/plugin/web` is imported * ✅ Verify token is valid and not expired * ✅ Confirm dashboard-id/metric-id exists * ✅ Check browser console for errors * ✅ Ensure CORS is properly configured * ✅ Use `JSON.stringify()` for object props * ✅ Check CSS specificity conflicts * ✅ Verify color format (use hex codes) * ✅ Test with `!important` to identify overrides * ✅ Enable canvas rendering for large datasets * ✅ Disable unnecessary features (loaders, underlying data) * ✅ Implement lazy loading for multiple components * ✅ Use `shouldFitFullScreen` for better performance Check our comprehensive troubleshooting guide for additional solutions # Dashboard App Filter Source: https://docs.usedatabrain.com/developer-docs/helpers/dashboard-app-filter Dashboard App Filter: Instruction Manual * In your dashboard, create a new filter. * In the "Apply On" section, enable the *App Filter* option. Dashboard Filters setup with Apply On and App Filter enabled ### Method 1: Passing from Component * Use the parameter `"global-filter-options"` to pass values directly from a component to the dashboard filter. * Configuration changes based on the Filter Type and the Data Type. 1. **Single-Select Filter:** * For *string-based* filters, pass just the value: ```javascript theme={"dark"} global-filter-options={ JSON.stringify({ "Filter name for a string datatype": { defaultOption: 'James Smith' }, "Filter name for a number datatype": { defaultOption: {min: 100, max: 900}, // number range }, "Filter name for a date datatype": { defaultOption: {startDate: '2024-01-01', endDate: '2024-12-31'}, // date range }, }) } ``` 2. **Multi-Select Filter:** * For *string-based* filters, pass an array of values: ```javascript theme={"dark"} global-filter-options={ JSON.stringify({ "Filter name for a string datatype": { options: [ { value: 'James Smith', label: 'James' }, { value: 'Olivia Johnson', label: 'Olivia' }, { value: 'Emma Brown', label: 'Emma' }, ], // in case you want the drop down. defaultOption: ['James Smith', 'Emma Brown'], // selected values }, "Filter name for a number datatype": { defaultOption: {min: 100, max: 900}, // number range }, "Filter name for a date datatype": { defaultOption: {startDate: '2024-01-01', endDate: '2024-12-31'}, // date range }, }) } ``` Refer the below "Options" document for further queries. *** ### Method 2: Passing from Guest Token * You can link a guest token here to pass the filter values dynamically.\ Refer the below document to generate a guest token. ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { // single string "name": "Eric", // multi select "country": ["USA", "CANADA"] || "USA", // based on filter variant(select or multi-select) // date-picker "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-3-23" }, // range "price": { "min": 1000, "max": 5000 } }, "isShowOnUrl": true // true/false } ] } } ``` *** ### Method 3: Handling Large Selections with SQL Integration Filters with a large number of options (e.g., over 500), manually passing all values becomes inefficient. With SQL integration, you can dynamically fetch options from your database, simplifying the process. The SQL query specified under the `"sql"` key dynamically fetches the latest values from the specified database table. ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { // single string "name": "Eric", "country": { "sql": "SELECT \\\"name\\\" FROM \\\"public\\\".\\\"countries\\\" WHERE isEnabled=true", "columnName": "name" }, // date-picker "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-3-23" }, // range "price": { "min": 1000, "max": 5000 } }, "isShowOnUrl": true // true/false } ] } } ``` #### Key Benefits: 1. **Dynamic Updates**: The SQL query retrieves only the latest relevant options from your database. * Example: `SELECT "name" FROM "public"."countries" WHERE isEnabled=true` fetches active country names. 2. **Efficiency**: Eliminates the need to manually manage large datasets in the configuration. 3. **Flexibility**: The `columnName` specifies the field in the query result to use as filter values. 4. **Scalability**: Handles thousands of options seamlessly, reducing payload size and improving performance. This approach is ideal for keeping filters updated with minimal effort, ensuring they remain efficient and user-friendly. # Dashboard id Source: https://docs.usedatabrain.com/developer-docs/helpers/dashboard-id Accessing Dashboard ID In the Data App that you created (see API Token to know more about how to create a data app), click on Embed Info > Add New Embed. Provide the workspace name, select embed type as dashboard, provide the dashboard to get the dashboard id. The Embed ID is the dashboard id that you can use. # Embed Functions Source: https://docs.usedatabrain.com/developer-docs/helpers/embed-functions You can add your own buttons with embed functions. To integrate and make use of specific **embed functions** within the `dbn-dashboard` component, you first need to locate the component with `dbn-dashboard` className on the webpage. ```ts theme={"dark"} const dbnDashboard = document.querySelector( 'dbn-dashboard' )?.shadowRoot?.querySelector('.dbn-dashboard') as HTMLElement & { onClickCreateMetric?: () => void; onClickManageMetrics?: () => void; onClickScheduleReports?: () => void; onClickCustomizeLayout?: () => void; }; ``` Now you can add the buttons on your screen with these specific functions in the **onClick** event of those buttons, here's an example: ```tsx theme={"dark"} ``` ### Embed Functions Overview There are four functions provided by the embed: ```ts theme={"dark"} onClickCreateMetric(): It will open the create metric modal. ``` ```ts theme={"dark"} onClickManageMetrics(): It will open the manage metrics modal. ``` ```ts theme={"dark"} onClickScheduleReports(): It will open the schedule reports modal. ``` ```ts theme={"dark"} onClickCustomizeLayout(): It will enable the customize layout mode. ``` > ⚠️ **Note:** The functions will work only if you haven't disabled the respective operations. Also, you need to disable `showDashboardActions` in `options` in `dbn-dashboard` component, if you don't want to see the buttons provided by it that perform these actions and want to customize the buttons yourself. # End User Dashboard Creation Source: https://docs.usedatabrain.com/developer-docs/helpers/end-user-dashboard-creation Description of your new file. 1. **Create a Datamart** Create a Datamart in "Data Studio" page. Kindly refer the below link on how to create datamarts: 2. **Create a Workspace with Datamart connection** Workspace with Datamart For more details, kindly refer the below link: 3. \*\*Create a Dashboard \*\* Create Dashboard For more details, kindly refer the below link: 4. **Create a DataApp** Createa Data App For more details, kindly refer the below link: 5. **Generate API Token** * Navigate to the Data App. * In the "API Token" section, generate the API token by specifying the name of company and description (optional) Generate API Token **API Methods** **Cloud Databrain:** ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/dataApp/embed/{method_path} ``` **Self-hosted Databrain:** ```http theme={"dark"} POST /api/v2/dataApp/embed/{method_path} ``` 6. **Create a Dashboard** ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/dataApp/dashboardEmbed/create ``` ```http theme={"dark"} POST /api/v2/dataApp/dashboardEmbed/create ``` ```json theme={"dark"} { "dashboardId": "id", "clientId": "102", "templateDashboardId": "demo-sales-test-dashboard", // dashboard id to clone filters "metadata": {"created_at": "2025-09-25", "name":"lyman's dashboard", "descriptions":"created for 102 client id, it's end user dashboard embed"}, // metadata of dashboard "workspaceName": "Demo Sales API", "accessSettings": { "datamartName": "Demo Sales API Test Datamart", "isAllowAiPilot": true, "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": true, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": false, "isAllowCreateDashboardView": false, "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "clientColumn": "client id", "name": "demo_sales" } ] } } // database tenancy don't require table list ``` * `dashboardId` – Unique external dashboard ID (must not already exist). * `workspaceName` – Must match a valid workspace linked to the API token's company. * `clientId` – Identifier of the client for which the dashboard is being created. * `templateId` – Optional. External dashboard ID of a template to clone. * `accessSettings` – Required. Defines permissions and feature access for the embed. Create Dashboard API Result 7. **Create Guest token by passing Client ID and DataApp Name** When you need a guest token that you want to use across dashboards and metrics. All you have to do is pass `clientId`, `dataAppName`. If `expiryTime` is not passed, the token will not expire. ## Generating GUEST TOKEN for your Dashboard ### Headers | Name | Type | Description | | :-------------- | :----- | :----------------- | | Authorization\* | String | Bearer (API Token) | ### Request Body | Name | Type | Description | | :------------- | :----- | :----------------------------------------------------------------------------------------------------------------------------------- | | dataAppName\* | String | Your Data App Name | | clientId\* | String | Client ID for whom this guest token is generated. (`"clientId": "None"` if no tenancy is selected for connected datasource/datamart) | | params | Object | Additional Params: `dashboard`, `appFilters` | | expiryTime | Number | In milliseconds | | datasourceName | String | Datasource name from Data Studio (\*important and supported in multi-datasource connection in workspace) | **Example Response: 200 OK "token": "..."** ```json theme={"dark"} when the response is successful it returns a token that you can pass to the frontend. ```

When the response is successful it returns a token that you can pass to the frontend.

### Simple Request Body ```json theme={"dark"} { "clientId": "102", "dataAppName": "Demo Sales API" } ``` Once you acquire the guest token, you can seamlessly pass it to your frontend application, where it can be integrated with the web component Create Embed Created Dashboard in embed * The created dashboard will mimic the filter behavior of the cloned dashboard if a Template ID is provided. * Once the dashboard is created, users can start building metrics. ```json theme={"dark"} { "embedId": "id", "accessSettings": { "datamartName": "Demo Sales API Test Datamart", "isAllowAiPilot": true, "isAllowEmailReports": false, "isAllowManageMetrics": true, "isAllowMetricCreation": true, "isAllowMetricDeletion": true, "isAllowMetricLayoutChange": true, "isAllowMetricUpdate": true, "isAllowUnderlyingData": true, "isAllowCreateDashboardView": false, "metricCreationMode": "DRAG_DROP", "tableTenancySettings": [ { "clientColumn": "client id", "name": "demo-sales" } ] } } ``` Update Dashboard API Result ```json theme={"dark"} { "embedId": "id" } ``` Delete Dashboard API Result # End User Metric Creation Source: https://docs.usedatabrain.com/developer-docs/helpers/end-user-metric-creation 1. **Create a Datamart** Create a Datamart in "Data Studio" page. Kindly refer the below link on how to create datamarts: 2. **Create a Workspace with Datamart connection** For more details, kindly refer the below link: 3. **Create a Dashboard with few defined metrics** For more details, kindly refer the below link: 4. **Create a DataApp** For more details, kindly refer the below link: 5. **Create an Embed Type using either dashboard or metric** * Navigate to the Data App. * In the "Embed Info" section, create an embed type using workspace name, embed type: dashboard or metric, name of dashboard or metric. 6. **Generate API Token** In the "API Token" section, generate the API token by specifying the name of company and description (optional) 7. **Configure options in Access control section** * Navigate to the Data App. * In the "Access Control" section, enable **Metric Creation** for the embed. Metric creation is controlled at three levels, in priority order: 1. **Guest token** — if the token sets `permissions.isDisableMetricCreation: true`, metric creation is off no matter what else is configured. 2. **Data App Access Control** — the server-side setting you enable in this step. 3. **Embed component** — `options.disableMetricCreation` on `dbn-dashboard` hides the UI client-side. There is no `isAllowMetricCreation` embed prop — the component option is `disableMetricCreation`. 8. **Create Guest token by passing Client ID and DataApp Name** When you need a guest token that you want to use across dashboards and metrics. All you have to do is pass `clientId`, `dataAppName`. If `expiryTime` is not passed, the token will not expire. **Cloud Databrain:** ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/guest-token/create ``` **Self-hosted Databrain:** ```http theme={"dark"} POST /api/v2/guest-token/create ``` ## Generating GUEST TOKEN for your Dashboard/Metric Component ### Headers | Name | Type | Description | | --------------- | ------ | ------------------ | | Authorization\* | String | Bearer (API Token) | ### Request Body | Name | Type | Description | | -------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------- | | dataAppName\* | String | Your Data App Name | | clientId\* | String | Client ID for whom this guest token is generated. (`"clientId": "None"` if no tenancy is selected for connected datasource/datamart) | | params | Object | Additional Params: `appFilters`, `rlsSettings`, `userIdentifier`, `allowedEmbeds` — see [Token Body](/developer-docs/helpers/token-body) | | expiryTime | Number | In milliseconds. If omitted, the token never expires | | datasourceName | String | Datasource name from Data Studio (\*important and supported in multi-datasource connection in workspace) | **Example Response: 200 OK "token": "..."** ```json theme={"dark"} when the response is successful it returns a token that you can pass to the frontend. ```

When the response is successful it returns a token that you can pass to the frontend.

### Simple Request Body ```json theme={"dark"} { "clientId": "Vaccine", "dataAppName": "Procurement App" } ``` Once you acquire the guest token, you can seamlessly pass it to your frontend application, where it can be integrated with the web component. 9. **End User Metric Creation / Updation** **Metric Creation** * Click on the "+Create Metric" button near the settings icon * Drag and drop necessary dimensions and measures to create the metric * Then, click on "Save" icon at the top right corner and specify metric details to save the metric to dashboard **Metric Updation** * View the metric in full screen and click on the "Edit Metric" button * Update the metric according to your requirements and save it to dashboard # LLM Architecture Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-architecture Architecture of flow of information. # LLM Connectors Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors Getting Started with Configuring Popular LLMs with DataBrain Databrain makes it easy to unlock the full potential of Large Language Models (LLMs) within your analytics environment. Whether you're looking to enhance dashboards with intelligent summaries, generate insights on demand, or enable conversational data exploration — LLM integration is your gateway to smarter, faster decision-making. Below, we explore some of the most popular LLM integrations available in DataBrain and how they can enhance your analytics strategy. Each section provides a comprehensive, step-by-step guide to help you configure and integrate your preferred LLM—enhancing the accessibility, interpretability, and intelligence of your data workflows. # Azure Open AI Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/azure-open-ai ## Step 1: Configure Azure Open AI Navigate to the **LLMs** section on settings page and click on **+LLM** Choose **Azure Open AI** from the list. In the **Configure Azure Open AI** panel: * **Name**: Enter a descriptive name (e.g., `Azure GPT Assistant`) * **Base URL**: Use your Azure Open AI endpoint URL in the format: `https://.openai.azure.com/` * **API Key**: Paste your valid Azure Open AI API Key * **Deployment Name**: Enter the deployment name of your model (e.g., `deploy-gpt-35`) Click **Authenticate** to activate the integration. ## Step 2: Connect LLM to Workspace Navigate to your desired workspace and click on ⚙️ **settings icon** next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom * From the **LLM** dropdown, choose the Azure Open AI model you just configured Optionally enable **Metric Summary** and choose the summary **Type** from the following options:\ Technical and Insight Summary, Forecast and Trend Analysis, Comparative and Anomaly Detection, Custom. Click **Save** to apply changes. You’ve successfully connected Azure Open AI with your Databrain workspace!\ Your integration is now live — enabling advanced Azure-powered LLM capabilities for intelligent insights, contextual summaries, and seamless data exploration across your dashboards. # Claude AI Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/claude-ai ## Step 1: Configure Claude AI Navigate to the **LLMs** section on settings page and click on **+LLM** Choose Claude AI from the list. In the **Configure Claude AI** panel: * **Name**: Enter a descriptive name (e.g., `Claude Assistant`) * **API Key**: Paste your valid Claude AI API Key Click **Authenticate** to activate the integration. *** ## Step 2: Connect LLM to Workspace Navigate to your desired workspace and click on ⚙️ **settings icon** next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom * From the **LLM** dropdown, choose the Claude AI model you just configured Optionally enable **Metric Summary** and choose the summary **Type** from the following options: Technical and Insight Summary, Forecast and Trend Analysis, Comparative and Anomaly Detection, Custom. Click **Save** to apply changes. You’ve successfully connected Claude AI with your Databrain workspace!\ Your integration is now live — enabling intelligent summaries, contextual analysis, and seamless natural language interactions with your data. # Gemini Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/gemini ### Step 1: Configure Gemini Navigate to the **LLMs** section on the **Settings** page and click on **+LLM**. Choose **Gemini** from the list. In the **Configure Gemini** panel: * **Name**: Enter a descriptive name (e.g., `Gemini Workspace Assistant`). * **API Key**: Paste your valid **Gemini API Key**. * **Model**: Enter the **Gemini model name** you want to use (e.g., `gemini-1.5-pro`). Click **Authenticate** to activate the integration. Configure Gemini *** ### Step 2: Connect LLM to Workspace Navigate to your desired **workspace** and click on the ⚙️ **settings icon** next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom. * From the **LLM dropdown**, choose the **Gemini model** you just configured. Optionally enable **Metric Summary** and choose the summary **Type** from the following options: * *Technical and Insight Summary* * *Forecast and Trend Analysis* * *Comparative and Anomaly Detection* * *Custom* Click **Save** to apply changes. Workspace Settings You’ve successfully connected Gemini with your Databrain workspace!\ Your integration is now active — empowering you to leverage Gemini’s LLM capabilities for advanced metric summaries, contextual insights, and intelligent data exploration within your dashboards. # Llama Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/llama ### Step 1: Configure Llama 1. Navigate to the **LLMs** section on settings page and click on **+LLM** 2. Choose Azure Open AI from the list. 3. In the **Configure Llama** panel: * **Name**: Enter a descriptive name (e.g., `LLaMA Workspace Assistant`). * **Base URL**: Provide the endpoint URL from your provider in the format: `https://.ai/v1` * **API Key**: Paste your valid API Key provided by the LLaMA service provider. * **Model Name**: Enter the model identifier (e.g., `meta-llama/Llama-3-**`). 4. Click **Authenticate** to complete the integration. ### Step 2: Connect LLM to Workspace Navigate to your desired workspace and click on `settings icon` next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom * From the **LLM** dropdown, choose the Llama model you just configured Optionally enable **Metric Summary** and choose the summary **Type** from the following options: Technical and Insight Summary, Forecast and Trend Analysis, Comparative and Anomaly Detection, Custom. Click **Save** to apply changes. You’ve successfully connected Llama with your Databrain workspace!\ Your integration is now active — enabling Llama-powered metric summaries, contextual insights, and intelligent natural language interactions across your dashboards. # Mixtral Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/mixtral ## Step 1: Configure Mixtral Navigate to the `LLMs` section on the **Settings** page and click on **+LLM**. Choose **Mixtral** from the list. In the **Configure Mixtral** panel: * **Name**: Enter a descriptive name (e.g., *Mixtral AI Assistant*). * **Base URL**: Provide the endpoint URL from your provider in the format: `https://.ai/v1` * **API Key**: Paste your valid API Key provided by the Mixtral service provider. * **Model Name**: Enter the full model name (e.g., *mistralai/Mixtral-*\*\*) Click **Authenticate** to activate the integration. *** ## Step 2: Connect LLM to Workspace Navigate to your desired workspace and click on `settings icon` next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom * From the **LLM** dropdown, choose the Mixtral model you just configured Optionally enable **Metric Summary** and choose the summary **Type** from the following options:\ Technical and Insight Summary, Forecast and Trend Analysis, Comparative and Anomaly Detection, Custom. Click **Save** to apply changes. You’ve successfully connected Mixtral with your Databrain workspace!\ Your integration is now active — enabling Mixtral-powered LLM capabilities for intelligent insights, automated metric summaries, and seamless data interaction across your dashboards. # Open AI Source: https://docs.usedatabrain.com/developer-docs/helpers/llm-connectors/open-ai ### Step 1: Configure Open AI Navigate to the **LLMs** section on the settings page and click on **+LLM**. Choose Open AI from the list. In the **Configure Open AI** panel: * **Name**: Enter a descriptive name (e.g., `GPT Workspace Assistant`). * **API Key**: Paste your valid Open AI API Key. Click **Authenticate** to activate the integration. ### Step 2: Connect LLM to Workspace Navigate to your desired workspace and click on the **⚙️ settings icon** next to the workspace name. Under the **General** tab: * Scroll to the **LLM** section near the bottom * From the **LLM** dropdown, choose the Open AI model you just configured Optionally enable **Metric Summary** and choose the summary **Type** from the following options:\ Technical and Insight Summary, Forecast and Trend Analysis, Comparative and Anomaly Detection, Custom. Click **Save** to apply changes. You’ve successfully connected Open AI with your Databrain workspace!\ Your LLM integration is now active — enabling automated metric summaries, insights, and intelligent data exploration across your dashboards. # Metric App Filter Source: https://docs.usedatabrain.com/developer-docs/helpers/metric-app-filter Metric App Filter: Instruction Manual Using the App Filter in Metric: * In your Metric, create a new filter * In the "Apply On" section, enable the "App Filter" option Metric filter configuration with App Filter enabled ### Method 1: Passing from Component * Use the parameter `"metric-filter-options"` to pass values directly from a component to the metric filter. * Configuration changes based on the Filter Type and the Data Type. 1. **Single-Select Filter:** * For *string-based* filters, pass just the value: ```javascript theme={"dark"} metric-filter-options={JSON.stringify({ // note that invalid options will be filtered out "Filter name for a string datatype": { options: [ { value: 'James Smith', label: 'James' }, { value: 'Olivia Johnson', label: 'Olivia' }, { value: 'Emma Brown', label: 'Emma' }, ] // should have unique elements defaultOption: 'James Smith', // value of the selected option }, "Filter name for a number datatype": { options: [{ value: 1, label: 'user_1' }, { value: 2, label: 'user_2' }], // should have unique elements defaultOption: 1, // value of the selected option }, ``` 2. **Multi-Select Filter:** * For *string-based* filters, pass an array of values: ```javascript theme={"dark"} metric-filter-options={JSON.stringify({ // note that invalid options will be filtered out "Filter name for a string datatype": { options: [ { value: 'James Smith', label: 'James' }, { value: 'Olivia Johnson', label: 'Olivia' }, { value: 'Emma Brown', label: 'Emma' }, ] // should have unique elements defaultOption: ['James Smith', 'Olivia Johnson' ], // value of the selected option }, "Filter name for a number datatype": { options: [{ value: 1, label: 'user_1' }, { value: 2, label: 'user_2' }], // should have unique elements defaultOption: 1, // value of the selected option }, ``` Refer the below “Options” document for further queries. *** ### Method 2: Passing from Guest Token * You can link a guest token here to pass the filter values dynamically.\ Refer the below document to generate a guest token. ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params" : { "appFilters": [{ “metricId”: “The id of the metric you want to have app filters”, “values”: { “paid_orders”: true, “amount”: 500, “country”: ["USA", "CANADA"] || "USA" // based on filter variant(select or multi select) } }] } } ``` *** ### Method 3: Handling Large Selections with SQL Integration Filters with a large number of options (e.g., over 500), manually passing all values becomes inefficient. With SQL integration, you can dynamically fetch options from your database, simplifying the process. The SQL query specified under the `"sql"` key dynamically fetches the latest values from the specified database table. ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "appFilters": [ { "metricId": "The id of the metric you want to have app filters", "values": { "paid_orders": true, "amount": 500, "country": { "sql": "SELECT \"name\" FROM \"public\".\"countries\" WHERE isEnabled=true", "columnName": "name" } } } ] } } ``` #### Key Benefits: 1. **Dynamic Updates:** The SQL query retrieves only the latest relevant options from your database. * Example: `SELECT "name" FROM "public"."countries" WHERE isEnabled=true` fetches active country names. 2. **Efficiency:** Eliminates the need to manually manage large datasets in the configuration. 3. **Flexibility:** The `columnName` specifies the field in the query result to use as filter values. 4. **Scalability:** Handles thousands of options seamlessly, reducing payload size and improving performance. This approach is ideal for keeping filters updated with minimal effort, ensuring they remain efficient and user-friendly. # Metric ID Source: https://docs.usedatabrain.com/developer-docs/helpers/metric-id Accessing the Metric ID In the Data App that you created (see API Token to know more about how to create a data app), click on Embed Info > Add New Embed. Provide the **workspace name**, select embed type as **metric**, provide the **dashboard** which includes that metric and then metric to get the metric id. The Embed ID is the metric id that you can use. # Options Source: https://docs.usedatabrain.com/developer-docs/helpers/options The extra options/parameters that you can pass for your Web Component. This page contains raw component examples. For a comprehensive, organized reference with detailed explanations, see our [Component Options Reference](/developer-docs/helpers/component-options-reference). StackBlitz View the comprehensive, organized reference guide with detailed explanations, examples, and best practices for all component options. ### Dashboard Component ```jsx theme={"dark"} { return
content
; }} long-description-config={JSON.stringify({ width: "", fontColor: "", })} disable-fullscreen enable-title-click-fullscreen={true} admin-theme-options={JSON.stringify({ general: { name: "themeName", fontFamily: "font family like sans, roboto etc", datePickerFormat: "format", }, dashboard: { backgroundColor: "red", ctaColor: "blue", ctaTextColor: "blue", selectBoxSize: "small", selectBoxVariant: "floating", selectBoxBorderRadius: "20px", selectBoxTextColor: "red", }, cardDescription: { fontSize: "10px", fontWeight: "400", color: "red", elementColor: "#64748b", // element layout descriptions (.dbn-metric-element-description); optional }, cardTitle: { fontSize: "20px", fontWeight: "400", color: "red", elementColor: "#0f172a", // element layout titles (.dbn-metric-element-title); optional }, chart: { palettes: [ { name: "pallete name", colors: ["red", "blue", "green"], }, ], paletteOptions: ["palette1", "palette2"] // options from in palettes selected: "selected pallete name", chartFontFamily: "roboto", chartFontColor: "red", chartLetterSpacing: "12px", tooltip: { header: { fontFamily: "roboto", fontSize: "12px", fontWeight: "bold", fontColor: "red", }, label: { fontFamily: "roboto", fontSize: "12px", fontWeight: "bold", fontColor: "red", }, value: { fontFamily: "roboto", fontSize: "12px", fontWeight: "bold", fontColor: "red", }, }, }, cardCustomization: { padding: "20px", borderRadius: "10px", shadow: "0px 10px 10px 0px rgba(13, 13, 13, 0.05)", disableShadowOnHover: true, disableStroke: true, metricStrokeColor: "blue", }, })} theme-name="Name of the theme you want to apply from app settings ui theming" chart-columns={JSON.stringify([ { isEnabled: true, metricId: "comparison_filter89", dimensions: ["name"], measures: ["count of order_id"], }, ])} hide-dashboard-filters={JSON.stringify(["workspace"])} theme={JSON.stringify({ button: { primaryText: "white", primary: "red", secondaryText: "black", secondary: "white", }, checkbox: { checked: "orange", unChecked: "blue", }, switch: { enabled: "orange", disabled: "blue", }, drillBreadCrumbs: { fontFamily: "clash grotesk", fontColor: "black", activeColor: "red", }, multiSelectFilterDropdown: { badgeColor: "blue", badgeTextColor: "black", }, })} custom-chart-settings={JSON.stringify({ // See the Custom Chart Settings Reference section in Component Options Reference for the full schema // Example: // labelSettings: { XAxisStyle: { size: { defaultValue: 12, canEdit: true } } } })} translation-dictionary={JSON.stringify({ "total sales": { en: "total sales", fr: "ventes totales", es: "ventas totales", de: "Gesamtumsatz", it: "vendite totali", pt: "vendas totais", zh: "总销售额", ja: "総売上", ko: "총 매출", hi: "कुल बिक्री", ar: "إجمالي المبيعات", ru: "общие продажи", }, })} language="fr" calendar-type="ind" chart-click-function="functionName" />; ``` ### Metric Component ```jsx theme={"dark"} ```

For the metric-filter-options prop, invalid options will be filtered out.

Server Event .
### FAQs As a web component, it does not automatically re-render upon prop changes. A common approach to address this is to force a re-render by displaying a loader and temporarily hiding the web component during prop updates. Instead of directly changing the props, you can set a temporary state to display the loader or hide the metric, then update the prop after a brief delay. ```javascript theme={"dark"} // React example const [isLoading, setIsLoading] = useState(false); const [dashboardProps, setDashboardProps] = useState(initialProps); const updateProps = async (newProps) => { setIsLoading(true); await new Promise(resolve => setTimeout(resolve, 100)); setDashboardProps(newProps); setIsLoading(false); }; return isLoading ?
Loading...
: ; ```
* `chart-colors` is a direct attribute on the component * `chartColors` is a property within the `options` object * Both serve the same purpose but `chartColors` in options takes precedence ```html theme={"dark"} ``` Use the various disable/hide options available: ```javascript theme={"dark"} const minimalDashboard = { hideDashboardName: true, hideMetricCardShadow: true, disableMetricCreation: true, disableLayoutCustomization: true, disableManageMetrics: true, showDashboardActions: false }; ``` For metric components: ```jsx theme={"dark"} ``` Common issues with JSON.stringify: 1. **Undefined values are omitted:** ```javascript theme={"dark"} // ❌ This will omit undefined properties const options = { color: undefined, size: 12 }; JSON.stringify(options); // {"size":12} // ✅ Use null or default values instead const options = { color: null, size: 12 }; ``` 2. **Functions are omitted:** ```javascript theme={"dark"} // ❌ Functions are not serialized const options = { onClick: () => {}, size: 12 }; // ✅ Use string references for callbacks const options = { onClickHandler: "myGlobalFunction", size: 12 }; ``` 3. **Circular references cause errors:** ```javascript theme={"dark"} // ❌ This will throw an error const obj = {}; obj.self = obj; JSON.stringify(obj); // TypeError: Converting circular structure to JSON ``` **Enable Debug Mode:** ```javascript theme={"dark"} // Add to your global scope window.databrainDebug = true; // Check browser console for detailed logs ``` **Common Debugging Steps:** 1. Open browser DevTools → Console 2. Look for error messages starting with "Databrain:" 3. Check Network tab for failed API requests 4. Verify token validity in Application → Local Storage 5. Test with minimal component configuration **Component Health Check:** ```javascript theme={"dark"} // Add this to test basic functionality const testComponent = () => { const testElement = document.querySelector('dbn-dashboard'); console.log('Component found:', !!testElement); console.log('Token present:', !!testElement?.getAttribute('token')); console.log('Dashboard ID:', testElement?.getAttribute('dashboard-id')); }; ``` **High Performance Impact:** * `disableMainLoader: false` - Shows loading animations * `disableUnderlyingData: false` - Loads additional data * `chart-renderer-type: "svg"` - More CPU intensive than canvas * Complex `chartAppearance` configurations **Optimization Recommendations:** ```javascript theme={"dark"} const performanceOptimized = { disableMainLoader: true, disableMetricLoader: true, disableUnderlyingData: true, shouldFitFullScreen: true }; ``` **For Large Datasets:** ```html theme={"dark"} ``` **Memory Usage:** * Limit simultaneous dashboard instances * Use lazy loading for multiple components * Consider component cleanup on unmount
# Custom Fiscal Year filter setup in DataBrain Source: https://docs.usedatabrain.com/developer-docs/helpers/options/custom-fiscal-year-filter-setup-in-databrain Step-by-step guide to set up an Indian Fiscal Year filter in DataBrain for region-specific data analysis. ## 1. Configure the Date filter * Navigate to the **dashboard** where you want to set up the **Fiscal Year filter**. * Then, add a **Date filter** and select **preset options: Last Year** and **This Year**. * In the **"Apply On"** section, choose the date column, then click **"Save"** to apply the filter to your dashboard. ## 2. View the changes in Dashboard By default, the **"Last Year"** filter displays data from **January 1, 2024 to December 31, 2024**, and the **"This Year"** filter shows data from **January 1, 2025 to December 31, 2025**. ## 3. Configure the Date filter To enable the **Indian Fiscal Year**, add the following option to the embed settings: calendar-type='ind' Refer to the documentation for more details: ## 4. View the changes in dashboard After enabling the Indian Fiscal Year filter, the date ranges adjust as follows: * **"Last Year"** now displays data from **April 1, 2023 to March 31, 2024**. * **"This Year"** now displays data from **April 1, 2024 to March 31, 2025**. **Yearly and quarterly time-series charts** will automatically follow the **Indian Fiscal Year (April to March)** # Override Language Source: https://docs.usedatabrain.com/developer-docs/helpers/override-language The `@databrainhq/plugin` package allows you to customize the language of your embedded components by passing a translation dictionary and specifying the desired language. ### Overview **Parameters:** * `translation-dictionary`: A JSON object that maps keys (e.g., metric names, description, table columns, chart legends & label...etc) to their translations in multiple languages. * `language`: A string representing the language code (e.g., `"en"`, `"fr"`, `"es"`) you want to use for the component's content. When both parameters are used, the component will display the content in the specified language, falling back to the key if a translation for the selected language is unavailable. ### Usage Example ````tsx theme={"dark"} ```tsx In this example, the label "total sales" will be displayed in French as "ventes totales." ### Fallback Mechanism * If the `language` prop is set to a language code not available in the dictionary, the component will display the default key value (e.g., `"total sales"`). * Ensure all required keys and translations are included in your dictionary to provide a seamless user experience. ```` # Server Event Source: https://docs.usedatabrain.com/developer-docs/helpers/server-event It is a function prop that detects and retrieves error or loading occurring within dashboard component, facilitating timely resolution and enabling various automated tasks to be triggered in response. To make use of `handle-server-event` in dbn-dashboard, you first need to define the function that you want to pass to this prop in the global object, here's an example: ```js theme={"dark"} window.databrainServerEvent = (code: string) => { if (code) { // do something } } ``` To implement it in dbn-dashboard component: ```html theme={"dark"} ``` This will attatch the funtion to the dbn-dashboard component, fetching the error or loading status which you can handle in your app. Below is the list of all the codes that you can get from dbn-dashboard: * TOKEN\_EXPIRED * UNAUTHORIZED\_ORIGIN * INVALID\_TOKEN * INVALID\_DASHBOARD\_ID * IS\_LOADING * DATA\_LOADED * ENTER\_FULL\_SCREEN\_MODE * EXIT\_FULL\_SCREEN\_MODE * ENTER\_SCHEDULED\_REPORT\_MODE * SAVE\_SCHEDULED\_REPORT * EXIT\_SCHEDULED\_REPORT\_MODE * ENTER\_CUSTOMIZE\_LAYOUT\_MODE * EXIT\_CUSTOMIZE\_LAYOUT\_MODE * SAVE\_LAYOUT * ENTER\_MANAGE\_METRICS\_MODE * ENTER\_METRICS\_GALLERY\_MODE * EXIT\_MANAGE\_METRICS\_MODE * EXIT\_METRICS\_GALLERY\_MODE * SAVE\_MANAGE\_METRICS * SAVE\_CLIENT\_GALLERY\_METRICS * ARCHIVE\_METRIC * DOWNLOAD\_METRIC * DOWNLOAD\_METRIC\_WITHOUT\_FILTERS * SAVE\_METRIC\_PNG * METRIC\_FILTER\_APPLIED * DASHBOARD\_FILTER\_APPLIED * CREATE\_METRIC * UPDATE\_METRIC * ENTER\_CREATE\_METRIC * ENTER\_EDIT\_METRIC * DATASET\_SEARCH\_FOCUSED * DATASET\_TABLE\_SELECTED * COLUMN\_DRAGGED\_TO\_DIMENSIONS * COLUMN\_DRAGGED\_TO\_MEASURES * COLUMN\_AGGREGATE\_CHANGED * CHART\_TYPE\_CHANGED * START\_DOWNLOAD\_ALL\_METRICS * DOWNLOAD\_ALL\_METRICS * START\_DASHBOARD\_PDF * EXPORT\_DASHBOARD\_PDF ***NOTE***: If you get error like `Property 'functionName' does not exist on type 'Window & typeof globalThis'`, add the type of window as any. # Token Body Source: https://docs.usedatabrain.com/developer-docs/helpers/token-body Here you will see what are the fields to pass in the body while creating a guest token. JSON body - * dataAppName (required string) - The name of the data app for which you are creating the guest token. * clientId (required string) - The primary key of the client/organization in the workspace for which you are creating the guest token. * params (optional JSON object) - Optional token parameters (filters, embed allowlisting, end-user identity, timezone). * permissions (optional JSON object) - Dashboard permission toggles. Boolean keys: `isEnableArchiveMetrics`, `isEnableManageMetrics`, `isEnableCreateDashboardView`, `isEnableMetricUpdation`, `isEnableCustomizeLayout`, `isEnableUnderlyingData`, `isEnableDownloadMetrics`, `isShowSideBar`, `isShowDashboardName`, `isDisableMetricCreation`. No other keys exist (there is no `permissions.dashboards`). * expiryTime (optional number, milliseconds) - How long the token stays valid, measured from the moment it is created. If omitted, the token never expires. * datasourceName(required string with multi data source connection) - The data source name to be used as data connection. (not applicable for datasource or datamart connection). * datamartName (optional string) - Scope the token to a specific Datamart. The body is validated strictly: any field not listed here is rejected with `INVALID_REQUEST_BODY`. `dataAppId`, `client_id`, and `tenant_id` are not valid fields — use `dataAppName` and `clientId`. body -> params (optional JSON object) - * rlsSettings (optional array of JSON object) - if you want to apply any rls settings then here you can pass the "metricId" for which you want to apply the filter and "values" which is an object of filter name and filter value. * appFilters (optional array of JSON object) - if you want to apply metric-level filters with the app filter variant then here you can pass the "metricId" for which you want to apply the filter and "values" which is an object of filter name and value. * dashboardAppFilters (optional array of JSON object) - dashboard-level filters to apply on a specific embedded dashboard. * allowedEmbeds (optional array of strings) - allowlist of IDs this token is allowed to load. Each entry must match the ID passed to the embed component (`dashboardId` attribute); embed IDs and dashboard IDs both resolve. Loading any other ID fails with `UNAUTHORIZED`. * userIdentifier (optional string) - unique identifier for the end-user to enable private/publish metrics in embeds. * timezone (optional string) - IANA timezone (e.g. `"America/New_York"`) for timezone-aware queries and date formatting. * accessPermissions (optional JSON object) - end-user filter controls: `isAllowEndUserDashboardFilter`, `isAllowEndUserMetricFilter`, `isAllowDashboardFilterNameChange`, and `isAllowMetricFilterNameChange` (booleans), plus optional `dashboardFilterColumns` and `metricFilterColumns` arrays of `{ tableName, columns }`. params -> rlsSettings (optional array of JSON object) - * metricId (required string) - the id of the metric you want to apply the rls filters which you can find on the metric page in the header below the metric name. * values (required JSON object) - the filters name and value pairs that you want to apply. params -> appFilters (optional array of JSON object) - * metricId (required string) - the id of the metric you want to apply the rls filters which you can find on the metric page in the header below the metric name. * values (required JSON object) - the filters name and value pairs that you want to apply. params -> hideDashboardFilters(optional array of strings) - * array of name of filters # Translate Source: https://docs.usedatabrain.com/developer-docs/helpers/translate The plugin components support multilingual translations using the language and translationDictionary props. This allows you to render metric titles, descriptions, and labels in the end user ```html theme={"dark"} ``` ### `translation-dictionary` Format The `translation-dictionary` is a simple object where: * Each **key** matches the exact text you want to translate (e.g., metric title, subtitle, label). * Each **value** is an object with translations in various language codes (`en`, `fr`, `es`, etc.). * **Longer and more descriptive keys should be placed first** to ensure they're matched before shorter or nested ones. Example: ```javascript theme={"dark"} const translationDictionary = { "Total Sales and Total Profit by Category": { en: "Total Sales and Total Profit by Category", fr: "Ventes totales et bénéfices totaux par catégorie", de: "Gesamtumsatz und Gesamtgewinn nach Kategorie", // ... }, "This metric provides a breakdown of financial outcomes across different groupings...": { en: "This metric provides a breakdown of financial outcomes across different groupings...", fr: "Cette mesure fournit une répartition des résultats financiers...", // ... }, "Note: Values represent aggregated figures...": { en: "Note: Values represent aggregated figures...", fr: "Remarque : Les valeurs représentent des chiffres agrégés...", // ... }, "Total Sales": { en: "Total Sales", fr: "Ventes Totales", // ... }, "Sum of Profit": { en: "Sum of Profit", fr: "Somme du bénéfice", // ... }, "Category": { en: "Category", fr: "Catégorie", // ... }, "Sales": { en: "Sales", fr: "Ventes", // ... }, "Product": { en: "Product", fr: "Produit", // ... } }; ``` Important Guidelines * 🔑 **Keys must match exactly**: The keys in `translation-dictionary` must exactly match the text in your dashboard configuration (e.g., metric titles, chart subtitles, dynamic labels). * 🧠 **Prefer longer keys first**: If multiple keys are substrings of each other, always define and check the longer, more descriptive one first. * 🌐 **Add all relevant labels**: Include all chart titles, subtitle blocks, footnotes, and section labels that might appear in a rendered dashboard. Fallback Behavior If a translation is **missing** for a given key/language: * The system will **fall back** to the original key. Dashboard in original language with default text and tooltips Dashboard translated with French labels using embed translation-dictionary # Workspace name Source: https://docs.usedatabrain.com/developer-docs/helpers/workspace-name Accessing and Editing Workspace Name On the Home page, navigate to the Workspaces section to view the list of Shared and Private workspaces. To edit a workspace name, click the Workspace Settings icon, update the name as desired, and click 'Save'. # How to embed? Source: https://docs.usedatabrain.com/developer-docs/how-to-embed Learn how to create a data app, generate API tokens, and create guest tokens for embedding Databrain dashboards in your application. * Navigate to the "Data" section in your app. * Look for the "Data Apps" option and select it. * Click on "**New Data App**" button. Provide the required information including naming it and configuring basic settings. Refer to "[**Dashboard ID**](https://docs.usedatabrain.com/developer-docs/helpers/dashboard-id)" for generating embed ID and refer "[**API TOKEN**](https://docs.usedatabrain.com/developer-docs/helpers/api-token)" for generating api token that will be used to generate "**guest token**" later. Once API Token is generated, create "**guest token**" with "**client ID**", which is a unique identifier for the client or user you're creating the token for and the **data app name** that you created above in the body. * Guest tokens are used for allowing temporary, limited access to your Data App. Image(12) Pn * Go to postman or any other API platform. * Set the URL as [**https://api.usedatabrain.com/api/v2/guest-token/create.**](https://api.usedatabrain.com/api/v2/guest-token/create) * In the Authorization tab, select type as "**Bearer Token**" and in token field add the "**API token**" that you created in your data app. * You'll need to specify a **Client ID**. * Click on "**Send**". The generated guest token will be associated with the provided Client ID and data app. Use the guest token and the embed ID to test your embed. # License Key Validation for Self-Hosted App Source: https://docs.usedatabrain.com/developer-docs/license-key-validation-for-self-hosted-app This guide is essential for self-hosted app users, detailing the process of license key validation and renewal. ### For Logged-In Users: 1. **Free Trial Period** * Upon starting the app, **a temporary license key** will be issued, providing access for a **15-day free trial period**. * During this trial, you will have full access to all features of the app. 2. **Post-Trial Access** At the end of the 15-day trial period, the temporary license key will automatically **expire**, and access to the app will be restricted. 3. **Requesting a New License Key** * To continue using the app beyond the trial period, a **new license key** is required. * Please share the app key with **our support team** in order to initiate the renewal process. 4. **License Key Renewal Process** * Upon receiving the expired key, **our team** will generate and provide a new license key. * This key will enable continued access to the app under the purchased plan. 5. **Re-authentication** * Once the new license key is received, kindly proceed to **re-authenticate** the app using the updated key. * Successful authentication will restore full access and ensure uninterrupted usage. ### For New Sign-Ins: 1. **Initial Login:** Upon your first login, you will be prompted to enter the license key. 2. **Enter License Key:** Paste your license key in the designated field and click 'Submit'. 3. **Re-authentication:** After submission, you will need to sign in again to activate your license. ### License Validity and Renewal * **Activation:** Your instance will remain active for the duration of your license key’s validity. * **Renewal Reminder:** Please note that the license key is valid until the specified expiry date. You will need to repeat these steps to update the license key upon expiration. # Client Setup Source: https://docs.usedatabrain.com/developer-docs/mcp-server/client-setup Detailed configuration instructions for each AI client This guide covers full configuration for each supported AI client, including file paths, restart steps, self-hosted setup, and optional API-token-only configuration. *** ## Configuration by Client ### Add via CLI ```bash theme={"dark"} codex mcp add databrain --env DATABRAIN_SERVICE_TOKEN=YOUR_SERVICE_TOKEN -- npx @databrainhq/mcp-server ``` Replace `YOUR_SERVICE_TOKEN` with your Databrain service token. ### Self-Hosted For a self-hosted Databrain instance, include the API URL: ```bash theme={"dark"} codex mcp add databrain \ --env DATABRAIN_SERVICE_TOKEN=YOUR_SERVICE_TOKEN \ --env DATABRAIN_API_URL=https://api.your-databrain.example.com \ --env DATABRAIN_DEMO_DOMAIN=https://demo.your-databrain.example.com \ -- npx @databrainhq/mcp-server ``` ### Verify ```bash theme={"dark"} codex mcp list ``` Start a new Codex session after adding or updating the server. ### Config File Location * **Project-level:** `.cursor/mcp.json` in your project root * **Global:** `~/.cursor/mcp.json` Project-level config takes precedence when both exist. ### Configuration ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` ### Restart After saving the config file, restart Cursor or reload the window (**Cmd+Shift+P** -> "Reload Window") to pick up the new MCP server. ### Config File Location * **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json` * **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` ### Configuration ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` ### Restart Fully quit Claude Desktop and reopen it. On macOS, use **Cmd+Q** to quit. ### Add via CLI ```bash theme={"dark"} claude mcp add databrain -- npx @databrainhq/mcp-server ``` ### Set Environment Variable Add to your shell profile (`.bashrc`, `.zshrc`, etc.): ```bash theme={"dark"} export DATABRAIN_SERVICE_TOKEN="" ``` Then reload your shell: ```bash theme={"dark"} source ~/.zshrc ``` ### Verify ```bash theme={"dark"} claude mcp list ``` You should see `databrain` in the list of configured servers. ### Config File Location `~/.codeium/windsurf/mcp_config.json` ### Configuration ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` ### Restart Restart Windsurf after saving the config file. ### Direct Execution The server uses stdio transport and works with any MCP-compatible client. ```bash theme={"dark"} export DATABRAIN_SERVICE_TOKEN="" npx @databrainhq/mcp-server ``` ### Programmatic Usage If your client accepts a command and arguments: * **Command:** `npx` * **Args:** `["@databrainhq/mcp-server"]` * **Env:** `{ "DATABRAIN_SERVICE_TOKEN": "" }` *** ## Self-Hosted Databrain If you're running a self-hosted Databrain instance, set `DATABRAIN_API_URL` to the API origin for that instance. ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "", "DATABRAIN_API_URL": "https://api.your-databrain.example.com", "DATABRAIN_DEMO_DOMAIN": "https://demo.your-databrain.example.com" } } } } ``` Checklist: * `DATABRAIN_API_URL` must be the API origin, not the dashboard URL. * The token must be minted from that same self-hosted instance. Tokens are not portable across instances. * The MCP client process must be able to reach the URL through your VPN, firewall, or certificate setup. * Set `DATABRAIN_DEMO_DOMAIN` if `get_demo_link` should use a custom preview host. *** ## API-Token-Only Mode By default, use a service token. It lets the MCP server discover resources, manage data apps, create API tokens, and run semantic-layer workflows. If you only need operations inside one existing data app, you can configure an API token instead: ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_API_TOKEN": "" } } } } ``` API-token-only mode is scoped to one data app. It supports embed, guest token, widget, demo link, and scheduled report metadata operations, but org-level discovery and setup tools require `DATABRAIN_SERVICE_TOKEN`. You can also provide both tokens: ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "", "DATABRAIN_API_TOKEN": "" } } } } ``` *** ## Environment Variables Reference | Variable | Required | Default | Description | | ------------------------- | ------------------------ | ------------------------------- | ------------------------------------------------------------------------------------------------- | | `DATABRAIN_SERVICE_TOKEN` | One of two | - | Org-level token from **Settings -> Service Tokens** | | `DATABRAIN_API_TOKEN` | One of two | - | Per-data-app token used for embed, widget, guest token, demo link, and report metadata operations | | `DATABRAIN_API_URL` | Required for self-hosted | `https://api.usedatabrain.com` | API base URL | | `DATABRAIN_DEMO_DOMAIN` | No | `https://demo.usedatabrain.com` | Hosted preview base URL for `get_demo_link` | At least one of `DATABRAIN_SERVICE_TOKEN` or `DATABRAIN_API_TOKEN` must be set. If both are set, service-token mode is used for org-level operations. *** ## Verifying the Connection After configuring your client, try asking your AI assistant: > **"Who am I authenticated as in Databrain?"** This calls `whoami` and confirms whether the server is running in service-token or API-token mode. Then ask: > **"List my Databrain data apps"** If you get a missing-token configuration error, double-check that the token is set in the `env` block of your MCP config and restart your client. See the [Troubleshooting guide](/developer-docs/mcp-server/troubleshooting) for common issues and solutions. # MCP Server Source: https://docs.usedatabrain.com/developer-docs/mcp-server/overview Add embedded analytics to your app using natural language. Connect the Databrain MCP server to any AI assistant and describe what you want. `@databrainhq/mcp-server` is available on [npm](https://www.npmjs.com/package/@databrainhq/mcp-server) and requires Node.js 18+. The Databrain MCP server lets you manage embedded analytics through your AI assistant. Instead of navigating the Databrain UI or calling REST APIs directly, describe what you want in plain English and the assistant handles the setup steps for you. ``` "Embed my sales dashboard in my React app" "Find valid client IDs for my workspace" "Add a widget to a customer's dashboard" "Dry-run this SQL as a Databrain metric" "Enable self-serve metric creation on this embed" "What was total revenue last month?" ``` The server implements the [Model Context Protocol](https://modelcontextprotocol.io) (MCP), an open standard that connects AI assistants to external tools and data sources. *** ## How It Works Tell your AI assistant what you need: embed a dashboard, find valid tenants, query data, customize theming, add customer-specific widgets, migrate SQL into a metric, enable self-serve analytics, or review scheduled report configuration. The server maps your request to the right Databrain actions, manages authentication, validates inputs, and applies production safeguards for writes. Your data apps, dashboards, embeds, tenants, widgets, workspace metrics, semantic layer, and scheduled report metadata are accessed through the Databrain API. Results flow back through the server to your assistant. *** ## MCP Server vs NPM Plugin Databrain offers two integration paths. Choose based on your workflow: | | MCP Server | NPM Plugin (`@databrainhq/plugin`) | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | **Best for** | Setting up and configuring embeds via AI assistant | Rendering embeds in your frontend | | **How it works** | Natural language in Codex, Cursor, Claude, Windsurf, or any MCP client | Web components (``, ``) | | **What it does** | Creates embeds, discovers tenants, manages tokens, configures themes/filters, queries data, edits widgets, enables self-serve analytics, generates frontend code | Renders dashboards and metrics in the browser | | **When you use it** | During development, setup, and ongoing embed maintenance | At runtime in your application | They're complementary, not competing. Use the MCP server to set up and maintain your embeds, then use the NPM plugin to render them in your app. The MCP server can generate plugin code via `generate_embed_code`. *** ## Key Capabilities Discover data apps, select dashboards, create embeds, and generate framework-specific frontend code through conversation. List valid `clientId` values from your tenancy database before creating guest tokens or editing customer dashboards. Ask questions in natural language. The AI converts them to SQL, runs the query, and returns results with chart suggestions. List, add, update, remove, or generate widgets for a specific customer's dashboard without changing other customers. Validate warehouse-tested SQL, dry-run Databrain metric writes, and apply only after explicit production confirmation. Create unpublished, unattached workspace-level metrics from validated SQL before deciding where to publish them. Customize colors, fonts, chart styles, responsive breakpoints, card styling, and access presets. Enable drag-and-drop or chat metric creation, configure filters, localize embeds, and lock down permissions. Populate, maintain, and auto-generate table/column descriptions to improve natural language query accuracy. *** ## Supported AI Clients The server uses stdio transport and works with any MCP-compatible client: * **Codex** - OpenAI's coding agent CLI * **Cursor** - IDE with built-in MCP support * **Claude Desktop** - Anthropic's desktop app * **Claude Code** - CLI tool for developers * **Windsurf** - Codeium's AI IDE * **Any MCP client** - Any tool that supports the Model Context Protocol *** ## What's Included The server ships with **36 tools**, **8 guided prompts**, and **11 built-in knowledge resources**. | Component | Count | Purpose | | ------------------------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------ | | [Tools](/developer-docs/mcp-server/tools-reference) | 36 | API operations for discovery, tenants, embeds, widgets, workspace metrics, semantic layer, metric migration, and reports | | [Prompts](/developer-docs/mcp-server/prompts-reference) | 8 | Guided workflows for common setup and production-safe maintenance tasks | | Knowledge Resources | 11 | Built-in references the AI consults automatically | Datasource and workspace setup still happen in the Databrain UI. Datamarts can be planned with `create_datamart` in `dry_run` mode and created only with `confirm: "APPLY_TO_PRODUCTION"`. Workspace-level metrics can be planned with `create_workspace_metric` in `dry_run` mode and created or updated only after the same explicit confirmation. Re-applying with the same `metricId` updates the metric in place and re-hydrates Dimensions/Measures from the new SQL. The semantic layer is populated and maintained via MCP tools. ### Built-in Knowledge Resources The server bundles reference documentation that your AI assistant reads automatically when needed. | Resource | Content | | ----------------------- | ----------------------------------------------------------------------------------------- | | Getting Started | Entity model, onboarding checklist, token types | | API Reference | Key Databrain API endpoints and examples | | Embedding Guide | Framework-specific code for React, Next.js, Vue, Angular, Svelte, SolidJS, and vanilla JS | | Theme Reference | Admin theme, component theme, and chart appearance schemas | | Web Component Reference | `` and `` attributes | | Filter Reference | Filter types, operators, runtime filters, and dashboard filters | | Self-Serve Reference | Permission flags and metric creation modes | | Semantic Layer Guide | Semantic layer setup for AI-powered querying | | Multi-Tenancy Guide | Row-level security, `clientId` patterns, and tenant isolation | | Use Case Guides | Tool sequences and decision guidance for common flows | | Permission Schema | Embed `accessSettings`, guest token permissions, precedence rules, and limitations | *** ## Environment Variables At least one credential is required. Use a service token for full setup and management flows; use an API token only when you are operating inside one data app. | Variable | Required | Default | Description | | ------------------------- | ------------------------ | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `DATABRAIN_SERVICE_TOKEN` | One of two | - | Org-level token from **Settings -> Service Tokens**. Powers discovery, tenant lookup, setup, data app management, semantic layer, and production-safe datamart and workspace-metric operations. | | `DATABRAIN_API_TOKEN` | One of two | - | Per-data-app token. Created automatically during setup via `create_api_token`, or provided manually for a single data app. | | `DATABRAIN_API_URL` | Required for self-hosted | `https://api.usedatabrain.com` | API origin for cloud or self-hosted Databrain. | | `DATABRAIN_DEMO_DOMAIN` | No | `https://demo.usedatabrain.com` | Base URL used by `get_demo_link` for hosted dashboard previews. | *** ## Authentication Model Databrain uses two token types: **Service Token** - org-level, set once in your MCP config. Used for datasource/datamart/workspace discovery, tenant lookup, data app and API token management, dashboard listing, semantic layer operations, natural language querying, `create_datamart`, and `create_workspace_metric`. **API Token** - scoped to a single data app. Used for embed operations, guest token generation, widget operations, data-app-scoped dashboard listing, and scheduled report metadata. The MCP server can create and activate API tokens via `create_api_token` when a service token is configured. Production write tools default to dry-run where supported and require explicit confirmation before applying changes. *** ## Get Started Set up in 2 minutes Common use cases All 36 tools # Prompts Reference Source: https://docs.usedatabrain.com/developer-docs/mcp-server/prompts-reference All 8 guided prompts available in the Databrain MCP server Prompts are guided workflows that your AI assistant can follow. They encode best practices, safe sequencing, and the correct tool order for common tasks. You can trigger a prompt by asking naturally or by referencing the prompt name directly. ## At a Glance | Prompt | Category | What It Does | | ------------------------------ | -------------------- | ----------------------------------------------------------------------------------------------------------- | | `embed-existing-dashboard` | Setup | Embed a dashboard that already exists in the Databrain UI | | `embed-blank-dashboard` | Setup | Create per-client dashboard embeds for multi-tenant apps | | `brand-my-embed` | Customization | Customize colors, fonts, cards, charts, responsive layout, and access presets | | `query-data` | Data exploration | Query a datamart with natural language and use the semantic layer | | `populate-semantic-layer` | Data setup | Generate and save table/column descriptions, synonyms, and examples | | `customize-customer-dashboard` | Dashboard updates | Add, update, remove, or generate widgets for one customer's dashboard | | `sql-to-metric-migration` | Production migration | Validate SQL, dry-run metric creation/update on a customer dashboard, then apply with explicit confirmation | | `sql-to-workspace-metric` | Internal analytics | Create or update an unpublished workspace metric from SQL (no clientId / not attached to a dashboard) | *** ## Setup Prompts **Embed a dashboard you've already built in the Databrain UI.** The most common starting point. Walks through data app selection, API token creation, workspace and dashboard selection, embed creation or reuse, guest token generation, and frontend code generation. **Example asks:** * "Embed my sales dashboard in my React app" * "Set up a Databrain embed for my dashboard" * "I want to embed the revenue overview dashboard" **Tools used:** `list_data_apps` -> `list_api_tokens` / `create_api_token` -> `list_workspaces` -> `list_dashboards` -> `list_embeds` -> `create_embed` -> `get_embed_details` -> `generate_guest_token` -> `generate_embed_code` [See full workflow ->](/developer-docs/mcp-server/workflows#embed-an-existing-dashboard) **Multi-tenant setup where each client gets their own dashboard.** Creates per-client dashboard embeds using `clientId` for customer-specific dashboard copies. This is the right flow when customers need different layouts, self-serve metrics, or per-client dashboard isolation. **Example asks:** * "Create per-client dashboard embeds for my SaaS app" * "Set up multi-tenant embeds with separate dashboards per customer" * "I need each client to have their own dashboard copy" **Tools used:** `list_data_apps` -> `list_api_tokens` / `create_api_token` -> `list_dashboards` -> `list_datamarts` -> `create_embed` per client -> `generate_guest_token` -> `generate_embed_code` [See full workflow ->](/developer-docs/mcp-server/workflows#multi-tenant--per-client-embeds) *** ## Data Prompts **Query your data with natural language and manage semantic context.** Ask questions about your data without setting up dashboards. The assistant verifies the datamart and semantic layer before calling `ask_question`. **Example asks:** * "What was total revenue last month?" * "Compare sales across regions for Q1" * "Show me the top 10 products by revenue" **Tools used:** `list_datamarts` -> `get_semantic_layer` -> `update_semantic_layer` or `start_semantic_layer_generation` if needed -> `ask_question` [See full workflow ->](/developer-docs/mcp-server/workflows#query-data-with-natural-language) **Generate and save table/column descriptions to improve natural language querying.** Bootstraps the semantic layer by generating business-friendly descriptions, synonyms, and example questions, then pushes them to Databrain. **Example asks:** * "Set up the semantic layer for my orders datamart" * "Add descriptions to all my tables and columns" * "Improve the semantic layer quality for better query accuracy" **Tools used:** `list_datamarts` -> `get_semantic_layer` -> `update_semantic_layer` -> `get_semantic_layer` -> `ask_question` [See full workflow ->](/developer-docs/mcp-server/workflows#populate-the-semantic-layer) *** ## Embed Customization Prompt **Customize colors, fonts, chart styles, responsive layout, cards, and access presets.** Applies visual theming to match your product's branding. Supports theme presets, custom colors, font family, card styling, chart appearance, responsive breakpoints, and access presets. **Example asks:** * "Make my embed match our brand: primary color #4F46E5, dark mode" * "Apply the corporate theme and use Inter font" * "Customize chart colors to use our brand palette" **Tools used:** `list_embeds` -> `get_embed_details` -> `customize_embed_theme` -> `update_embed` when advanced patching is needed [See full workflow ->](/developer-docs/mcp-server/workflows#brand-and-theme-an-embed) *** ## Customer Dashboard Prompts **Add, modify, remove, or generate widgets for one customer's dashboard.** This flow is designed for customer-specific dashboard updates. The assistant asks for `clientId` and `dashboardName`, resolves the required resources automatically, and keeps every change scoped to one customer. **Example asks:** * "Add the Calls per Day widget to Acme's dashboard" * "Remove the billing widget for one client only" * "Generate a widget showing disqualification reasons for this customer" * "Give me a demo link so I can see what this client sees" **Tools used:** `list_tenants` when `clientId` is unknown -> `list_widgets` -> `generate_widget` or `add_widget` -> `update_widget` / `remove_widget` -> `list_widgets` -> `get_demo_link` [See full workflow ->](/developer-docs/mcp-server/workflows#customize-a-customer-dashboard) **Production-safe SQL-to-metric migration on a customer dashboard.** Converts validated warehouse SQL into a Databrain metric/widget with an explicit validation, dry-run, review, apply, and verification sequence. Use this when the metric should appear on a customer's embedded dashboard (`clientId` required). **Example asks:** * "Validate this SQL as a new metric on my operations dashboard" * "Dry-run creating this converted query as a metric, then show me the plan" * "Apply the approved metric migration" **Tools used:** `list_workspaces` -> `list_dashboards` -> `list_widgets` -> `validate_metric_spec` -> `create_or_update_metric_from_query` in `dry_run` -> `create_or_update_metric_from_query` in `apply` with `confirm: "APPLY_TO_PRODUCTION"` -> `list_widgets` -> `get_demo_link` [See full workflow ->](/developer-docs/mcp-server/workflows#sql-to-metric-migration) **Create or update an unpublished workspace metric from SQL (internal analytics).** Turns validated warehouse SQL into a workspace-scoped metric using the org service token. No `clientId`, and the metric is not attached to a dashboard. Pass an existing `metricId` to update in place — the query and Dimensions/Measures are re-hydrated; omit `metricId` to create. **Example asks:** * "I have this SQL — make it a metric in Databrain, but don't attach it to a dashboard" * "Update the SQL on my existing workspace metric and refresh Dimensions/Measures" * "Dry-run an unpublished Revenue by Region workspace metric" **Tools used:** `list_workspaces` -> `discover_datasource_schema` -> `create_workspace_metric` in `dry_run` -> `create_workspace_metric` in `apply` with `confirm: "APPLY_TO_PRODUCTION"` [See full workflow ->](/developer-docs/mcp-server/workflows#create-an-unattached-workspace-metric) *** ## Prompt Behavior * Prompt flows are interactive. The assistant presents results and waits for user input before the next mutating step. * Token and resource details stay in your MCP configuration and Databrain workspace. The assistant does not need service tokens, API tokens, data app IDs, datasource IDs, or embed IDs unless you provide them proactively. * Use `list_tenants` to discover valid `clientId` values from the workspace tenancy database before guest-token, demo-link, scheduled-report, or customer-dashboard widget work. * Use `externalMetricId`, not `metricId`, for `update_widget` and `remove_widget`. * `create_datamart`, `create_workspace_metric`, and `create_or_update_metric_from_query` apply operations require `confirm: "APPLY_TO_PRODUCTION"`. *** ## Related See these prompts in action with end-to-end walkthroughs Detailed docs for every tool # Quickstart Source: https://docs.usedatabrain.com/developer-docs/mcp-server/quickstart Get the Databrain MCP server running in 2 minutes You'll need a Databrain account, Node.js 18+, and an MCP-compatible AI client. A service token is recommended because it unlocks the full setup flow. ## Prerequisites * **Node.js 18+** - check with `node --version` * **A Databrain account** - [sign up here](https://app.usedatabrain.com/users/sign-up) if you don't have one * **An AI client** - Codex, Cursor, Claude Desktop, Claude Code, Windsurf, or another MCP-compatible client * **A Databrain credential** - preferably `DATABRAIN_SERVICE_TOKEN` *** 1. Log in to [Databrain](https://app.usedatabrain.com) 2. Go to **Settings -> Service Tokens** 3. Create a new token and copy it Keep your service token secure. It provides org-level access to Databrain resources. Add the MCP server configuration to your client. Pick your client below: Add the MCP server with your service token: ```bash theme={"dark"} codex mcp add databrain --env DATABRAIN_SERVICE_TOKEN=YOUR_SERVICE_TOKEN -- npx @databrainhq/mcp-server ``` Verify the server is configured: ```bash theme={"dark"} codex mcp list ``` Start a new Codex session after adding the server. Add to `.cursor/mcp.json` (project-level) or `~/.cursor/mcp.json` (global): ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` ```bash theme={"dark"} claude mcp add databrain -- npx @databrainhq/mcp-server ``` Set your token in the shell that launches Claude Code: ```bash theme={"dark"} export DATABRAIN_SERVICE_TOKEN="" ``` Add to `~/.codeium/windsurf/mcp_config.json`: ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` The server uses stdio transport. Set environment variables and run: ```bash theme={"dark"} export DATABRAIN_SERVICE_TOKEN="" npx @databrainhq/mcp-server ``` For detailed per-client instructions, API-token-only mode, restart steps, and self-hosted configuration, see the [Client Setup Guide](/developer-docs/mcp-server/client-setup). Open your AI assistant and ask: > **"Who am I authenticated as in Databrain?"** This calls `whoami` and confirms whether the MCP server is running with a service token or API token. Then ask: > **"List my Databrain data apps"** If everything is configured correctly, you'll see your available data apps. If you see a configuration error saying that no token is set, double-check that the token is in the `env` block of your MCP config and restart your AI client. See [Troubleshooting](/developer-docs/mcp-server/troubleshooting) for more help. Now try a real task: > **"Set up a Databrain embed for my dashboard"** The assistant walks you through each step interactively: picking your data app, selecting a workspace and dashboard, creating or reusing an embed, generating a guest token, and generating frontend code. Other things to try: > **"Add a widget to a customer's dashboard"** > **"List tenants for my workspace so I can pick the right clientId"** > **"Dry-run creating this SQL query as a Databrain metric"** > **"Enable self-serve metric creation on this embed"** > **"Brand my embed to match our company colors"** That's it. The assistant handles the Databrain API so you can focus on building. *** ## Credential Modes | Mode | When to use it | What works | | ------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | Service token | Recommended default | Full discovery, tenant lookup, setup, semantic layer, data app management, and production-safe datamart and workspace-metric operations | | API token | Existing single-data-app embed work | Embed operations, guest tokens, widget operations, demo links, and scheduled report metadata for that data app | If both tokens are configured, the MCP server prefers `DATABRAIN_SERVICE_TOKEN` for org-level operations and can activate per-data-app API tokens during setup. *** ## Next Steps Step-by-step guides for common tasks Detailed configuration per client All 36 tools # Tools Reference Source: https://docs.usedatabrain.com/developer-docs/mcp-server/tools-reference All 36 tools available in the Databrain MCP server The MCP server provides 36 tools organized by category. Your AI assistant picks the right tools automatically based on what you ask. Datasource and workspace setup are completed in the Databrain UI. Datamarts can be planned with `create_datamart` in `dry_run` mode and created only with `confirm: "APPLY_TO_PRODUCTION"`. *** ## Auth Modes | Auth | Used for | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Service Token | Org-level discovery, tenant lookup, data app and API token management, dashboard listing by workspace, semantic layer operations, natural language querying, datamart creation, and workspace-level metric creation | | API Token | Embed operations, guest token generation, data-app-scoped dashboard listing, widget operations, demo links, and scheduled report metadata | | No Databrain API call | Code generation or identity checks that do not call Databrain APIs | Production write tools default to dry-run where supported and require explicit confirmation before applying changes. *** ## Session & Identity | Tool | Description | Auth | | -------- | ------------------------------------------------------- | --------------------- | | `whoami` | Return the credential mode currently used for API calls | No Databrain API call | Use `whoami` before mutating operations when you need to confirm whether the session is running with a service token or an API token. *** ## Infrastructure - Exploration and Setup 6 tools for discovering infrastructure and managing production-safe datamart setup. | Tool | Description | Auth | | ---------------------------- | ------------------------------------------------------------------------------ | ------------- | | `list_datasources` | List active datasources in your organization | Service Token | | `discover_datasource_schema` | Inspect tables and columns in a datasource | Service Token | | `list_datamarts` | List datamarts with table counts and semantic layer scores | Service Token | | `list_workspaces` | List workspaces with datamart and datasource connections | Service Token | | `sync_datasource` | Trigger a datasource schema sync to refresh table and column metadata | Service Token | | `create_datamart` | Dry-run or apply creation of a datamart from selected tables and relationships | Service Token | ### `create_datamart` Safety `create_datamart` defaults to `mode: "dry_run"` and returns a preview of the datamart configuration. Applying the write requires: ```json theme={"dark"} { "mode": "apply", "confirm": "APPLY_TO_PRODUCTION" } ``` Key inputs include `name`, `datasourceName`, `tableList`, `relationships`, optional `tenancySettings`, or an advanced JSON configuration. *** ## Data Apps & Tokens 6 tools for managing data apps, tenants, and API tokens. These are usually handled automatically during embed setup. | Tool | Description | Auth | | ------------------ | --------------------------------------------------------------------- | ------------- | | `list_data_apps` | List data apps in your organization, optionally filtered by workspace | Service Token | | `list_tenants` | List available tenants/clients from the workspace tenancy database | Service Token | | `create_data_app` | Create a new data app | Service Token | | `list_api_tokens` | List API tokens for a data app; omit `dataAppName` to auto-resolve | Service Token | | `create_api_token` | Create and activate an API token for the current MCP session | Service Token | | `rotate_api_token` | Rotate an API token and activate the replacement for the session | Service Token | API tokens are scoped to one data app. The MCP server can create or rotate them when `DATABRAIN_SERVICE_TOKEN` is configured, so users should not paste API tokens into chat. Use `list_tenants` to find authoritative `clientId` values before creating guest tokens or editing tenant-scoped dashboards. *** ## Embeds 6 tools for creating, configuring, previewing, and theming embedded dashboards. | Tool | Description | Auth | | ----------------------- | ------------------------------------------------------------------------------------------------- | --------- | | `create_embed` | Create a standard embed or a multi-tenant dashboard embed with `clientId` | API Token | | `list_embeds` | List embed configurations; use `list_tenants` for authoritative client discovery | API Token | | `get_embed_details` | Get full embed configuration including access settings and theme | API Token | | `update_embed` | Patch embed access settings, permissions, options, filters, localization, theme, or name | API Token | | `customize_embed_theme` | Apply theme presets, colors, fonts, cards, chart appearance, responsive layout, or access presets | API Token | | `get_demo_link` | Generate the hosted preview URL for a dashboard embed scoped to a `clientId` | API Token | ### Embed Creation Shape For standard dashboard embeds, pass `dashboardId`, `workspaceName`, and `accessSettings: { datamartName }`. For per-client dashboard embeds, also pass `clientId`. The tool fills required `isAllow*` access settings with secure defaults, so only pass the flags the user explicitly wants enabled. ### Theme and Advanced Config Use `customize_embed_theme` for visual theming and access presets. Use `update_embed` for advanced embed changes such as filters, localization, permissions, or embed options. ### Demo Links `get_demo_link` returns the same kind of hosted preview URL as the Databrain UI's "Share Demo Link" flow. It uses `DATABRAIN_DEMO_DOMAIN` when configured. *** ## Runtime Integration 2 tools for generating guest tokens and frontend integration code. | Tool | Description | Auth | | ---------------------- | -------------------------------------------------------------------------------- | --------------------- | | `generate_guest_token` | Generate a server-side guest token for frontend embedding | API Token | | `generate_embed_code` | Generate code for React, Next.js, Vue, Angular, Svelte, SolidJS, or vanilla HTML | No Databrain API call | Guest tokens should be generated in your server-side application and passed to the frontend component. Never expose API tokens in browser code. *** ## Query & Semantic Layer 5 tools for natural language querying and data documentation. | Tool | Description | Auth | | -------------------------------------- | ---------------------------------------------------------------------------------- | ------------- | | `ask_question` | Ask a natural language question; returns data, SQL reasoning, and chart suggestion | Service Token | | `get_semantic_layer` | Inspect semantic layer metadata, synonyms, and completion score | Service Token | | `update_semantic_layer` | Add or update table/column descriptions, synonyms, example questions, and context | Service Token | | `start_semantic_layer_generation` | Start semantic-layer auto-generation for a datamart | Service Token | | `get_semantic_layer_generation_status` | Poll the semantic-layer generation job status | Service Token | `ask_question` requires a datamart and a populated semantic layer. If results are poor, inspect the semantic layer first and improve descriptions before re-running the question. *** ## Dashboards & Widgets 9 tools for dashboard discovery, workspace-level metrics, and customer-scoped widget management. | Tool | Description | Auth | | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | | `list_dashboards` | List dashboards globally, by workspace, or by data app | Service Token / API Token | | `list_widgets` | List widgets on a customer dashboard; returns `externalMetricId`, `metricId`, name, publish state, and creator | API Token | | `validate_metric_spec` | Validate a SQL-backed metric target without saving it | API Token | | `create_or_update_metric_from_query` | Dry-run or apply a SQL-backed metric create/update | API Token | | `create_workspace_metric` | Dry-run or apply create-or-update of a workspace-level metric (unpublished/unattached by default). Pass an existing `metricId` to update in place and re-hydrate Dimensions/Measures from the new SQL | Service Token | | `add_widget` | Add a widget by cloning a template widget, supplying a metric configuration, or using a generated draft | API Token | | `update_widget` | Patch a widget by `externalMetricId` for one customer's dashboard | API Token | | `remove_widget` | Soft-delete a widget for one `clientId` only | API Token | | `generate_widget` | Generate a widget draft from a natural-language prompt; does not persist by itself | API Token | ### Customer-Scoped Widget Flow For non-technical widget workflows, provide `clientId` and `dashboardName`; include `workspaceName` only if dashboard names are ambiguous. If you do not know the `clientId`, call `list_tenants` with the workspace first. The tools resolve data app, datasource, embed ID, and integration details automatically. Use `externalMetricId` for `update_widget` and `remove_widget`. Do not use the user-facing `metricId` slug for those operations. ### SQL-to-Metric Safety `create_or_update_metric_from_query` and `create_workspace_metric` default to `mode: "dry_run"`. Applying requires: ```json theme={"dark"} { "mode": "apply", "confirm": "APPLY_TO_PRODUCTION" } ``` Use `validate_metric_spec` first for dashboard-attached metric/widget changes, then dry-run, then apply only after the user reviews the plan. Use `create_workspace_metric` for internal (non-embed) workspace metrics — create by omitting `metricId`, or update by passing an existing `metricId` so the query and Dimensions/Measures are rewritten in place while publish/archived/draft state is preserved. ### `create_workspace_metric` Upsert Behavior `create_workspace_metric` upserts on `metricId`: * **Omit `metricId`** to create. The slug is derived from `name`, so re-running with the same name targets the same metric rather than creating a duplicate. * **Pass an existing `metricId`** to update that metric in place. The new SQL is saved and Dimensions/Measures are re-derived from the query output columns so the metric editor stays populated. * On update, archived/draft and publish state are preserved. The metric stays unattached to any dashboard unless you publish/attach it as a separate step. *** ## Scheduled Reports | Tool | Description | Auth | | ------------------------ | ----------------------------------------------------------------------- | --------- | | `list_scheduled_reports` | List configured scheduled reports for a specific client/dashboard embed | API Token | This tool returns schedule metadata such as subject, next scheduled time, recipient count, chart count, and download format. *** ## Tool Count | Category | Count | | ---------------------- | ------ | | Session & Identity | 1 | | Infrastructure | 6 | | Data Apps & Tokens | 6 | | Embeds | 6 | | Runtime Integration | 2 | | Query & Semantic Layer | 5 | | Dashboards & Widgets | 9 | | Scheduled Reports | 1 | | **Total** | **36** | # Troubleshooting Source: https://docs.usedatabrain.com/developer-docs/mcp-server/troubleshooting Common issues and solutions for the Databrain MCP server ## Common Issues **Cause:** Neither `DATABRAIN_SERVICE_TOKEN` nor `DATABRAIN_API_TOKEN` is set, or your MCP client is not reading the configured `env` block. **Fix:** 1. Check that your token is in the `env` block of your MCP config. 2. Verify the token value has no extra spaces or quotes. 3. Restart your AI client after changing the config. ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "npx", "args": ["@databrainhq/mcp-server"], "env": { "DATABRAIN_SERVICE_TOKEN": "your-actual-token-here" } } } } ``` If the token is set correctly and the error persists, regenerate it in **Settings -> Service Tokens** in the Databrain UI. **Cause:** You configured only `DATABRAIN_API_TOKEN`. API tokens are scoped to one data app and cannot run org-level setup tools. **Fix:** Add `DATABRAIN_SERVICE_TOKEN` when you need discovery, data app management, API token creation, semantic layer operations, or datamart setup. API-token-only mode is still valid for embed operations, widget operations, guest tokens, demo links, and scheduled report metadata inside the configured data app. **Cause:** No workspace was selected, the selected workspace has no dashboards, or the configured token is scoped too narrowly. **Fix:** Ask the assistant: > "List my workspaces and then show dashboards" Dashboards are usually scoped to workspaces. If you see workspaces but no dashboards, verify that dashboards exist in the Databrain UI for that workspace. **Cause:** Usually a token, ID, domain, or guest token payload mismatch. **Fix:** 1. **Guest token generated server-side?** Never expose API tokens in frontend code. 2. **IDs match?** Verify the embed ID and dashboard ID. 3. **Domain whitelisted?** Check that your frontend's domain is allowed in the data app settings. 4. **Inspect the embed:** Ask the assistant: > "Check my embed configuration for issues" The assistant uses `get_embed_details` to inspect access settings, dashboard references, and token inputs. **Cause:** Existing guest tokens may still carry old configuration. **Fix:** After updating theme or options through `customize_embed_theme` or `update_embed`: 1. Regenerate the guest token with `generate_guest_token`. 2. Reload your application to use the new token. Guest tokens are generated server-side and should be refreshed after configuration changes that affect runtime behavior. **Cause:** The widget may be unpublished, the preview is using a stale guest token, or the wrong `clientId` was used. **Fix:** 1. Ask the assistant to call `list_widgets` for the target `clientId` and dashboard. 2. Confirm the widget has `isPublished: true` if it should appear to end users. 3. Generate a fresh `get_demo_link` URL. 4. If testing inside your own app, regenerate the app's guest token. **Cause:** Production writes require an explicit confirmation value. **Fix:** Run the dry-run first, review the returned plan, then apply only after approval: ```json theme={"dark"} { "mode": "apply", "confirm": "APPLY_TO_PRODUCTION" } ``` This applies to `create_or_update_metric_from_query` and production datamart creation through `create_datamart`. **Cause:** The semantic layer is empty, incomplete, or missing business context. **Fix:** Check its status: > "Check the semantic layer quality for my datamart" If descriptions or synonyms are missing, ask: > "Add descriptions and synonyms to improve query accuracy" The assistant can update metadata with `update_semantic_layer` or start semantic-layer generation with `start_semantic_layer_generation`. **Cause:** Usually a Node.js version issue or invalid environment variable. **Fix:** The MCP server requires Node.js 18 or higher: ```bash theme={"dark"} node --version ``` If you see a version below 18, update Node.js. Also verify `DATABRAIN_API_URL` and `DATABRAIN_DEMO_DOMAIN` are valid URLs when set. **Cause:** npm/npx is not installed or the client cannot fetch the package. **Fix:** 1. Ensure npm is installed: `npm --version` 2. Try running the package directly: ```bash theme={"dark"} npx @databrainhq/mcp-server ``` 3. If fetching the package hangs, install globally: ```bash theme={"dark"} npm install -g @databrainhq/mcp-server ``` Then update your config to use the global binary: ```json theme={"dark"} { "mcpServers": { "databrain": { "command": "databrain-mcp-server", "env": { "DATABRAIN_SERVICE_TOKEN": "" } } } } ``` *** ## Diagnostics Ask your assistant: > "Who am I authenticated as in Databrain?" This calls `whoami` and confirms whether the session is using a service token or API token. For embed issues, ask: > "Check my embed configuration for issues" The assistant uses `get_embed_details` to inspect access settings and dashboard references, then regenerates a guest token if runtime state changed. For customer dashboard issues, ask: > "List widgets for this client and give me a demo link" The assistant uses `list_widgets` and `get_demo_link`. *** ## Known Limitations | Area | Limitation | Workaround | | --------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | | **Datasource setup** | Datasources are connected in the Databrain UI | Create datasources in the Databrain UI, then use `list_datasources`, `discover_datasource_schema`, and `sync_datasource` | | **Workspace setup** | Workspaces are created in the Databrain UI | Create workspaces in the Databrain UI, then use `list_workspaces` and dashboard workflows | | **Transport** | stdio only; no HTTP/SSE transport yet | Use `npx` with your MCP client's config file | | **Production writes** | Datamart and SQL-to-metric apply operations require explicit confirmation | Run dry-run first, review the plan, then apply with `confirm: "APPLY_TO_PRODUCTION"` | | **Scheduled reports** | `list_scheduled_reports` returns configured schedule metadata | Use Databrain reporting views for delivery status | *** ## Getting Help Start over with setup Verify your client config Review available tools # Workflows Source: https://docs.usedatabrain.com/developer-docs/mcp-server/workflows Step-by-step guides for the most common MCP server use cases The MCP server supports guided prompts that walk you through common tasks end-to-end. You can trigger these by asking naturally or by referencing the prompt name directly. Some use cases are direct tool workflows without a named prompt; you can still ask for them in natural language. ### Jump to a workflow Most common starting point Per-client dashboards Find valid client IDs Natural language to SQL Better AI querying Per-customer widget edits Dry-run then apply metrics Unattached metric drafts Colors, fonts, layout Self-serve, filters, i18n Report metadata *** ## Embed an Existing Dashboard The most common workflow. You have a dashboard built in the Databrain UI and want to embed it in your application. **Ask your AI assistant:** > "Embed my sales dashboard in my React app" **What happens:** The assistant calls `list_data_apps` and asks which data app to use when more than one exists. It checks `list_api_tokens` and creates one with `create_api_token` if needed. It calls `list_workspaces`, then `list_dashboards` scoped to the selected workspace. It checks `list_embeds`, then calls `create_embed` with `dashboardId`, `workspaceName`, and `accessSettings: { datamartName }` if a new embed is needed. It verifies with `get_embed_details`, generates a server-side guest token with `generate_guest_token`, and generates framework code with `generate_embed_code`. **Prompt name:** `embed-existing-dashboard` **What you get:** A working embed ID, a guest token payload pattern, and frontend code for React, Next.js, Vue, Angular, Svelte, SolidJS, or vanilla JS. *** ## Multi-Tenant / Per-Client Embeds Each customer gets their own dashboard copy with a stable `clientId`. **Ask your AI assistant:** > "Create per-client dashboard embeds for my SaaS app" **What happens:** 1. Lists data apps and ensures an API token exists. 2. Calls `list_tenants` to discover valid `clientId` values from the tenancy database. 3. Lists dashboards and asks which source or template dashboard to use. 4. Verifies the datamart and tenancy model. 5. Calls `create_embed` once per customer with `clientId`. 6. Generates guest tokens and frontend code. **Prompt name:** `embed-blank-dashboard` `clientId` must match between dashboard embed creation and guest token generation. For `create_embed`, pass only `accessSettings: { datamartName }` plus flags the user explicitly requests; the tool fills required access defaults. *** ## Discover Tenants / Client IDs Find valid customer identifiers before creating guest tokens, customer dashboards, widgets, demo links, or scheduled-report views. **Ask your AI assistant:** > "List tenants for my Demo Workspace" > "Find client IDs matching Acme before I edit a dashboard" **What happens:** The assistant uses `workspaceName` or `workspaceId`; if needed, it calls `list_workspaces` first. It calls `list_tenants`, optionally with `searchValue`, `datasourceId`, `datamartId`, or `limit`. It returns tenant labels and values so you can select the correct `clientId` for downstream embed, widget, guest-token, demo-link, or scheduled-report work. **Prompt name:** Ask naturally. This is usually a preflight for multi-tenant embed, customer-widget, guest-token, demo-link, or scheduled-report workflows. Prefer `list_tenants` when you need the authoritative customer list. `list_embeds` can show embed configuration, but tenant lookup comes from the workspace tenancy database. *** ## Query Data with Natural Language Ask questions about your data and get answers with chart suggestions. **Ask your AI assistant:** > "What was total revenue last month?" > "Show me the monthly revenue trend for the past year" > "Compare sales by region, broken down by quarter" **What happens:** The assistant calls `list_datamarts` to see which data models are available. It calls `get_semantic_layer` to verify table and column descriptions exist. If descriptions are missing, it improves them with `update_semantic_layer` or starts semantic-layer generation with `start_semantic_layer_generation`. It sends your question to `ask_question`, which converts it to SQL, executes the query, and returns results with a chart suggestion. Follow-up questions use conversation context for better accuracy: > "Now show only the top 5 regions" **Prompt name:** `query-data` *** ## Populate the Semantic Layer Bootstrap table and column descriptions to enable natural language querying. **Ask your AI assistant:** > "Check the semantic layer quality for my orders datamart and add descriptions" **What happens:** Calls `get_semantic_layer` to see the completion score and missing metadata. Generates business-friendly table and column descriptions, synonyms, and example questions. Writes metadata with `update_semantic_layer` or starts semantic-layer auto-generation with `start_semantic_layer_generation`. Re-checks the semantic layer score and optionally tests a sample `ask_question`. **Prompt name:** `populate-semantic-layer` *** ## Customize a Customer Dashboard Add, remove, or modify widgets for one customer's dashboard without affecting the template or other customers. **Ask your AI assistant:** > "Add the Calls per Day widget to Acme's dashboard" > "Remove the billing widget for this client only" > "Generate a widget showing disqualification reasons and add it to a client's embed" **What happens:** The assistant asks for `clientId` and `dashboardName`; if you do not know the `clientId`, it calls `list_tenants`. It asks for `workspaceName` only if the dashboard name is ambiguous. It calls `list_widgets` and presents widget names, publish state, `metricId`, and `externalMetricId`. It calls `add_widget`, `generate_widget`, `update_widget`, or `remove_widget` depending on the requested change. Customer-scoped writes are blocked when the dashboard is not tenant-scoped for that `clientId`. It calls `list_widgets` again, then `get_demo_link` so you can preview exactly what that `clientId` sees. **Prompt name:** `customize-customer-dashboard` `update_widget` and `remove_widget` require `externalMetricId`, which is returned by `list_widgets`. Do not use the user-facing `metricId` slug for those operations. *** ## SQL-to-Metric Migration Turn warehouse-validated SQL into a Databrain metric/widget on a customer dashboard with a production-safe validation and apply flow. **Ask your AI assistant:** > "Validate this SQL as a new metric on my operations dashboard" > "Dry-run creating this converted query as a metric, then show me the plan" **What happens:** Calls `list_workspaces`, `list_dashboards`, and `list_widgets` to confirm the target workspace, dashboard, client, and existing metric IDs. Calls `validate_metric_spec` to resolve data app, datasource, embed ID, dashboard ID, and conflicts. Calls `create_or_update_metric_from_query` with `mode: "dry_run"` and shows the exact plan. Calls `create_or_update_metric_from_query` with `mode: "apply"` and `confirm: "APPLY_TO_PRODUCTION"` only after the user approves. Calls `list_widgets` and `get_demo_link`. **Prompt name:** `sql-to-metric-migration` The workflow does not apply changes on the first pass. Applying requires the exact confirmation value `APPLY_TO_PRODUCTION`. *** ## Create an Unattached Workspace Metric Create or update a workspace-level metric from validated SQL without attaching it to a dashboard. This is useful when you want to stage a metric as unpublished first, fix SQL on an existing workspace metric, or refresh Dimensions/Measures after a query change. **Ask your AI assistant:** > "Create an unpublished workspace metric from this validated SQL, but do not attach it to a dashboard" > "Dry-run a workspace metric called Revenue by Region in my Analytics workspace" > "Update the SQL on my existing workspace metric and refresh its Dimensions and Measures" **What happens:** The assistant confirms the target `workspaceName` and datasource context (via `list_workspaces` / `discover_datasource_schema`). It calls `create_workspace_metric` with `mode: "dry_run"` to validate the name, SQL, optional `metricId`, datasource, and publish state without writing. When updating, the same `metricId` must be carried through dry-run and apply. It shows the validation result and output columns. On create, the metric will be workspace-level, unpublished by default, and unattached. On update, the existing metric is rewritten in place and Dimensions/Measures are re-derived from the new SQL while publish/archived/draft state is preserved. It calls `create_workspace_metric` with `mode: "apply"` and `confirm: "APPLY_TO_PRODUCTION"` only after you approve the write. **Prompt name:** `sql-to-workspace-metric`. Use `sql-to-metric-migration` instead when the metric should become a customer-dashboard widget. `create_workspace_metric` uses a service token, upserts on `metricId`, and does not publish or attach the metric by default. Applying requires the exact confirmation value `APPLY_TO_PRODUCTION`. *** ## Brand and Theme an Embed Customize colors, fonts, chart styles, responsive breakpoints, cards, and access presets to match your product. **Ask your AI assistant:** > "Make my embed match our brand: primary color #4F46E5, dark mode, Inter font" > "Apply the corporate theme preset and hide the dashboard name" **What happens:** 1. Identifies the target embed via `list_embeds` or `get_embed_details`. 2. Applies theme changes through `customize_embed_theme`. 3. Uses `update_embed` for advanced patches such as UI options, filters, localization, or permissions. 4. Regenerates the guest token if the frontend needs the new configuration. **Prompt name:** `brand-my-embed` *** ## Configure Embed Access, Filters, and Localization Enable self-serve analytics, add filters, localize embed text, or tighten permissions after an embed already exists. **Ask your AI assistant:** > "Enable metric creation on my embed with the visual builder" > "Add a date range filter and a region dropdown to my dashboard" > "Set up French translations for my embed" > "Lock down this embed so users can only view, not edit" **What happens:** The assistant calls `list_embeds` or `get_embed_details` to inspect the current access settings, filters, localization, and options. It calls `update_embed` for access settings, filters, localization, permissions, and advanced embed options. For self-serve metric creation, it sets metric-creation access flags and the requested mode, such as `DRAG_DROP` or `CHAT`. If frontend behavior depends on guest-token permissions or filters, it regenerates the guest token with `generate_guest_token`. It re-checks the embed with `get_embed_details` and can generate a demo link with `get_demo_link` for a tenant-scoped dashboard. **Prompt name:** Ask naturally. For purely visual changes, use `brand-my-embed`. *** ## Scheduled Reports Metadata Review scheduled report configuration for a customer/dashboard scope. **Ask your AI assistant:** > "List scheduled reports for this client's dashboard" **What happens:** 1. Resolves the dashboard by `dashboardName` and optional `workspaceName`, or by `embedId`. 2. Calls `list_scheduled_reports` with `clientId`. 3. Returns schedule metadata such as subject, next scheduled time, recipient count, chart count, and download format. This workflow lists configured schedules only. # Multi-Tenant Access Control Source: https://docs.usedatabrain.com/developer-docs/multi-tenant-access-control For your multi-tenant database architectures, establish atomic access controls through row-level policies (Database Tenancy & Table Tenancy), configurable in the Client Settings of our data source settings. ## How Our Row-Level Policies Work? Set row-level policies for each table using your data source's SQL language. DataBrain parses and applies these policies as Common Table Expressions (CTEs) during query generation. This step happens post-validation, just before sending the query to your database or warehouse. This method ensures user-specific data access, e.g., User A sees only their data. You can also define and assign dynamic variables in your SQL queries during token creation. ## Guest Token For a user to view the embedded DataBrain dashboard in your application, your backend must request a guest token from DataBrain. This request is specific to the user and utilizes their `userId` or `clientId`. **Example request payload:** ```json theme={"dark"} { "clientId": "7807dcd1-1919-474b-aba7-7f23a062d02f" } ``` These identifiers are then injected into your row-level policies, tailoring the data returned to the user based on these parameters. ## Example of Implementing a Row-Level Policy To ensure each user only sees data relevant to them in a consumers table, you would set up a row-level policy and create a specific token. Here’s how you can do it: ### Step 1: Defining the Row-Level Policy for the Customers Table Write a SQL query to define the policy: ```sql theme={"dark"} SELECT * FROM consumers WHERE id = 'client_id_variable' ``` `client_id_variable` is written as a bare quoted token — no curly braces. At query time Databrain replaces it with the `clientId` from the guest token. This query ensures that each user only accesses rows in the `consumers` table where their unique identifier matches the `id` column. ### Step 2: Generating a Token Use a `curl` command to generate a token for a specific user: ```bash theme={"dark"} curl -X POST --location 'https://api.usedatabrain.com/api/v2/guest-token/create' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer ' \ --data '{ "clientId": "7807dcd1-1919-474b-aba7-7f23a062d02f", "dataAppName": "your-data-app" }' ``` Both `clientId` and `dataAppName` are required on the v2 endpoint — the body is validated strictly. See the [Guest Token reference](/developer-docs/helpers/api-reference/token) for all optional fields. This process combines secure access control with customized data visibility, aligning with user-specific requirements. # 5-Minute Embedding Tutorial Source: https://docs.usedatabrain.com/developer-docs/quick-start/embedding-tutorial Get your first DataBrain dashboard embedded in 5 minutes This tutorial will get you up and running with a working embedded dashboard in just 5 minutes. We'll use a sample token and dashboard so you can see results immediately. ## What You'll Build By the end of this tutorial, you'll have: * ✅ A working embedded DataBrain dashboard * ✅ Understanding of the core embedding concepts * ✅ A foundation to build upon for production ## Prerequisites * Node.js 14+ installed * A React, Vue, or vanilla JavaScript project * 5 minutes of your time ⏱️ ## Step 1: Install the Package ```bash npm theme={"dark"} npm install @databrainhq/plugin ``` ```bash yarn theme={"dark"} yarn add @databrainhq/plugin ``` ```bash pnpm theme={"dark"} pnpm add @databrainhq/plugin ``` ## Step 2: Import the Plugin Add this import to your component or main file: ```javascript React theme={"dark"} import '@databrainhq/plugin/web'; function Dashboard() { return ( ); } export default Dashboard; ``` ```javascript Vue theme={"dark"} ``` ```javascript Vanilla JS theme={"dark"} import '@databrainhq/plugin/web'; // In your HTML document.body.innerHTML = ` `; ``` ```html HTML theme={"dark"} ``` ## Step 3: Run and View Start your development server and you should see the sample dashboard! 🎉 ```bash theme={"dark"} npm run dev # or npm start ``` **Congratulations!** You've embedded your first DataBrain dashboard. The dashboard you're seeing is a sample with demo data. ## Understanding What You Built Let's break down the code: ### The Component ```html theme={"dark"} ``` ### The Token ``` token="3affda8b-7bd4-4a88-9687-105a94cfffab" ``` This is a **guest token** - a temporary access token that allows viewing the dashboard. In production, you'll generate these from your backend. ### The Dashboard ID ``` dashboard-id="ex-demo" ``` This identifies which dashboard to display. Each dashboard in DataBrain has a unique ID. ## Next: Make It Production-Ready The sample above works great for testing, but for production you need to: ### 1. Create Your Own Dashboard 1. **Create your own dashboard** at [app.usedatabrain.com](https://app.usedatabrain.com/users/sign-up) 2. **Connect your database** as a data source 3. **Build your metrics and dashboards** 4. **Create a Data App** for embedding 5. **Generate tokens from your backend** (see below) Follow the full setup process ### 2. Generate Tokens from Your Backend **Security First:** Never expose your API token in frontend code. Always generate guest tokens from your backend. Here's how token generation works: **Token Flow:** ``` 1. User accesses dashboard ↓ 2. Frontend → Backend (request guest token) ↓ 3. Backend → DataBrain API (POST /guest-token/create) ↓ 4. DataBrain API → Backend (return guest token) ↓ 5. Backend → Frontend (return guest token) ↓ 6. Frontend → Dashboard component (render with token) ``` #### Backend Example (Node.js) ```javascript theme={"dark"} // backend/api/get-token.js import fetch from 'node-fetch'; export async function getGuestToken(userId) { const response = await fetch( 'https://api.usedatabrain.com/api/v2/guest-token/create', { method: 'POST', headers: { 'Authorization': `Bearer ${process.env.DATABRAIN_API_TOKEN}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: userId, dataAppName: 'your-data-app-name' }) } ); const data = await response.json(); return data.token; } ``` #### Frontend Example (React) ```javascript theme={"dark"} import { useEffect, useState } from 'react'; import '@databrainhq/plugin/web'; function Dashboard({ userId }) { const [token, setToken] = useState(null); useEffect(() => { // Fetch token from YOUR backend fetch('/api/get-databrain-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId }) }) .then(res => res.json()) .then(data => setToken(data.token)); }, [userId]); if (!token) return
Loading...
; return ( ); } ``` Complete token generation API docs ### 3. Customize the Dashboard Add options to customize appearance and behavior: ```html theme={"dark"} ``` Explore all customization options ## Embed a Single Metric You can also embed individual metrics instead of full dashboards: ```html theme={"dark"} ``` ## Common Customizations ```html theme={"dark"} ``` ```html theme={"dark"} ``` ```javascript theme={"dark"} const theme = { general: { primaryColor: '#FF6B6B', backgroundColor: '#F8F9FA', fontFamily: 'Inter' }, chart: { colors: ['#FF6B6B', '#4ECDC4', '#45B7D1'] } }; ``` ```javascript theme={"dark"} // Define global handler window.handleDashboardEvent = (event) => { console.log('Dashboard event:', event); }; ``` ## Framework-Specific Guides Get detailed integration guides for your framework: React integration guide Next.js with SSR support Vue 3 integration Angular setup guide Svelte integration Plain JavaScript ## Troubleshooting **Check:** * Plugin is imported before component renders * Token is valid and not expired * Dashboard ID is correct * No console errors **Solution:** Generate a fresh token from your backend. Guest tokens can be set to expire after a certain time. **Fix:** Ensure your domain is whitelisted in the Data App settings. Or generate tokens from your backend instead of frontend. **Try:** * Check for CSS conflicts * Use custom theme options * Wrap in a container div * Check z-index values Complete troubleshooting reference ## What's Next? You've successfully embedded a DataBrain dashboard! Here's what to explore next: Production-ready setup guide Multi-tenancy and access control Advanced customization options Complete API documentation ## Need Help? Experiment with live examples Get help from our team # Rate Limiting Configuration Source: https://docs.usedatabrain.com/developer-docs/rate-limiting Configure API rate limits for your self-hosted DataBrain deployment to balance security and performance DataBrain includes built-in rate limiting to protect your API against abuse, brute-force attacks, and accidental traffic spikes. In a self-hosted deployment, you have full control over these limits through environment variables. Rate limiting is **enabled by default** on all routes. No configuration is required for basic protection, but tuning the values for your specific traffic patterns is recommended. *** ## How It Works * Every incoming API request is tracked by the **client's IP address**. * Each rate limiter defines a **time window** and a **maximum number of requests** allowed within that window. * If a client exceeds the limit, they receive a `429 Too Many Requests` response until the window resets. * Standard rate limit headers are included in API responses so clients can monitor their remaining quota. If DataBrain runs behind a reverse proxy or load balancer (NGINX, AWS ALB, Cloudflare, etc.), make sure the proxy forwards the real client IP. DataBrain checks the `X-Client-IP` header first and falls back to the standard `X-Forwarded-For` header (via Express's built-in trusted proxy support) to identify individual clients. Without proper proxy configuration, all traffic may appear to come from a single IP and get rate-limited together. *** ## Environment Variables Set these in your `.env` file for the DataBrain API service (Express backend). All values represent the **maximum number of requests per client IP** within the given time window. ### General API Rate Limit Maximum requests per IP across **all API endpoints** within a **2-minute** window. This is the global rate limiter — it applies to every request before any route-specific limits are checked. **Important:** You should always explicitly set this variable in your `.env` file. If left unset, the rate limiter may not enforce the intended default of 500 requests. ### Authentication Rate Limits These protect login and identity-related endpoints against brute-force and credential-stuffing attacks. Maximum requests per IP to **authentication endpoints** within a **1-minute** window. Covers: sign-in, sign-up, SSO, password reset, invitation acceptance, and related auth flows. Maximum requests per IP to the **token refresh endpoint** within a **1-minute** window. Controls how frequently a client can request new access tokens. Maximum requests per IP to **OTP (one-time password) endpoints** within a **1-minute** window. Covers OTP generation and verification. ### Other Rate Limits Maximum requests per IP to **email-sending endpoints** within a **1-minute** window. Covers invitation emails, verification re-sends, and scheduled report triggers. Maximum requests per IP to the **demo database onboarding endpoint** within a **1-minute** window. Only relevant if you use the built-in demo database onboarding flow. *** ## Quick Reference | Variable | Default | Window | Protects | | ------------------------------------- | ------- | ------ | ----------------------------------- | | `RATE_LIMIT` | 500 | 2 min | All API routes (global) | | `AUTH_ROUTE_RATE_LIMIT` | 30 | 1 min | Login, sign-up, SSO, password reset | | `REFRESH_ROUTE_RATE_LIMIT` | 30 | 1 min | Token refresh | | `OTP_RATE_LIMIT` | 50 | 1 min | OTP generation and verification | | `EMAIL_RATE_LIMIT` | 50 | 1 min | Invitation and verification emails | | `ONBOARDING_DEMO_DATABASE_RATE_LIMIT` | 50 | 1 min | Demo database onboarding | Route-specific limits (auth, OTP, email) are applied **in addition to** the global limit. A request to a login endpoint must pass both the global `RATE_LIMIT` check and the `AUTH_ROUTE_RATE_LIMIT` check. *** ## Configuration Example Add these to your DataBrain API `.env` file: ```bash theme={"dark"} # --- Rate Limiting --- # Global: max requests per IP across all endpoints (2-minute window) RATE_LIMIT=500 # Auth routes: sign-in, sign-up, SSO, password reset (1-minute window) AUTH_ROUTE_RATE_LIMIT=30 # Token refresh endpoint (1-minute window) REFRESH_ROUTE_RATE_LIMIT=30 # OTP generation and verification (1-minute window) OTP_RATE_LIMIT=50 # Email sending: invitations, verification (1-minute window) EMAIL_RATE_LIMIT=50 # Demo database onboarding (1-minute window) ONBOARDING_DEMO_DATABASE_RATE_LIMIT=50 ``` After updating, restart the DataBrain API service for changes to take effect. *** ## Tuning for Your Deployment The default values are a good starting point for most deployments. Here's how to think about adjusting them: If you have a **small user base** (under \~100 users) and want tighter security, you can reduce limits — for example, halving `RATE_LIMIT` to `250` or lowering `AUTH_ROUTE_RATE_LIMIT` to `15`. Fewer legitimate users means fewer requests per IP, so tighter limits are less likely to cause false positives. Increase limits if you see legitimate requests getting `429` errors. Common scenarios: * **High-traffic embedded dashboards** — Many end users loading dashboards simultaneously can generate significant API traffic. Increase `RATE_LIMIT` as needed (e.g., to `1000` or higher). * **Shared IP / corporate NAT** — If many users share one public IP (offices, VPNs), they collectively consume one IP's quota. Raise `RATE_LIMIT` proportionally. * **Automated workflows** — CI/CD pipelines, bulk token generation, or automated testing can trigger auth limits. Raise `AUTH_ROUTE_RATE_LIMIT` or `REFRESH_ROUTE_RATE_LIMIT` for those environments. 1. **Start with the defaults** — they work well for most medium-sized deployments. 2. **Monitor 429 responses** in your logs or monitoring stack. 3. **Increase incrementally** if legitimate traffic is being blocked — double the value and observe. 4. **Avoid setting limits excessively high** — very high limits (e.g., `RATE_LIMIT=100000`) effectively disable rate limiting and remove protection against abuse. *** ## What Happens When a Limit Is Hit When a client exceeds a rate limit: 1. The API responds with HTTP status **`429 Too Many Requests`**. 2. The response body contains a descriptive error message (e.g., *"Too many requests, please try again later"*). 3. The client should wait until the current window expires before retrying. Responses include standard rate limit headers that clients can use to manage their request pace: * **`RateLimit`** — Combined header showing the current limit, remaining requests, and reset time (e.g., `limit=500, remaining=498, reset=120`) * **`RateLimit-Policy`** — Describes the rate limit policy in effect * **`Retry-After`** — Seconds to wait before retrying (included on 429 responses) If your backend integration receives a `429` response: 1. Read the `Retry-After` header to know when to retry. 2. Implement **exponential backoff** — wait 1s, then 2s, then 4s, etc. 3. Do not retry immediately in a tight loop — failed requests still count against the limit, so rapid retries will consume the next window's quota as soon as it resets. 4. Guest tokens are reusable — consider caching them on your backend rather than generating a new one for every page load. Refresh before the token's `expiryTime` to avoid `401` errors. *** ## Best Practices We strongly recommend explicitly setting the `RATE_LIMIT` variable in your `.env` file rather than relying on the default. This ensures predictable behavior and makes your configuration self-documenting. Rate limiting is based on client IP. If DataBrain sits behind NGINX, a cloud load balancer, or Cloudflare, ensure the proxy forwards the original client IP. DataBrain checks the `X-Client-IP` header first, then falls back to `X-Forwarded-For` (via Express trusted proxy support). Either header works — just make sure at least one is set. Without this, all requests appear to come from the proxy's IP, causing legitimate users to be rate-limited together. Guest tokens are reusable — once created, the same token can authenticate multiple requests until it expires. Instead of calling the guest token API on every page load, cache the token on your backend and reuse it for the same user and parameter combination. If you set an `expiryTime`, make sure to refresh the token **before** it expires. Expired tokens are periodically cleaned up and will return a `401` error once removed. Authentication endpoints are the most targeted by brute-force attacks. Keep `AUTH_ROUTE_RATE_LIMIT` and `OTP_RATE_LIMIT` conservative (30–50 per minute) unless you have a specific reason to increase them. Track 429 responses in your monitoring stack (DataDog, Grafana, etc.). A spike in 429s may indicate either an attack (good — the rate limiter is protecting you) or limits that are too tight for your traffic (adjust accordingly). *** ## Troubleshooting **Cause:** The reverse proxy is not forwarding the real client IP. **Fix:** Configure your proxy to forward the real client IP. DataBrain checks `X-Client-IP` first, then `X-Forwarded-For`. For NGINX, add: ``` proxy_set_header X-Forwarded-For $remote_addr; ``` For AWS ALB or Cloudflare, `X-Forwarded-For` is typically set automatically, but verify the header is reaching DataBrain. **Cause:** High-traffic pages generating too many API calls per IP. **Fix:** * Increase `RATE_LIMIT` to accommodate your peak traffic. * Cache guest tokens on your backend to reduce token-creation calls. * Ensure dashboards use caching (Workspace Settings → Cache Settings) to reduce repeated data queries. **Cause:** Auth rate limit exceeded, possibly from automated tests or repeated failed logins. **Fix:** Wait 1 minute for the window to reset. If this happens regularly for legitimate users, consider increasing `AUTH_ROUTE_RATE_LIMIT` slightly (e.g., from 30 to 50). *** ## Related Documentation Full overview of DataBrain security features Embedding configuration for self-hosted deployments Common issues and solutions for embedded dashboards Generate secure tokens for embedding # Error Codes Reference Source: https://docs.usedatabrain.com/developer-docs/reference/error-codes Every error string DataBrain can return — embed runtime errors, metric execution errors (E1001–E1007), and guest-token API errors — with cause and fix. Use this page to look up any error string you see in an embed, the metric builder, or a guest-token API response. ## Embed runtime errors These surface when an embedded dashboard or metric loads. Guest tokens are **database-backed UUIDs, not signed JWTs** — there is no signing key, so none of these errors are about signatures. | Error | Meaning | Fix | | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `INVALID_TOKEN` | The token UUID was **not found** in the deployment being queried | Check for a cloud vs self-hosted mismatch (a token exists only in the environment that minted it); confirm the embed receives the exact minted value; mint a fresh token | | `TOKEN_EXPIRED` | The token exists but its `expiryTime` has passed | Mint a fresh token; refresh cached tokens before the deadline. Tokens without `expiryTime` never expire | | `UNAUTHORIZED_ORIGIN` | The page's origin is not on the Whitelist Domains list | Add the origin (scheme-less `host[:port]`, wildcards like `*.example.com` supported) under your Data App's settings → **Whitelist Domains**. Whitelist *your* domain, not `api.usedatabrain.com`. The list is account-wide | | `UNAUTHORIZED` | The token is not allowed this request. On dashboard load: the ID isn't in the token's `params.allowedEmbeds`, or the dashboard doesn't belong to the token's Data App/workspace. On dashboard-filter, metric-filter, dashboard-view, or filter-alias requests: that capability isn't granted | For load errors: fix `allowedEmbeds` or the ID. For filter/view errors: enable the matching Data App access setting or grant it in the token (`params.accessPermissions.isAllowEndUserDashboardFilter`, `isAllowEndUserMetricFilter`, `isAllowDashboardFilterNameChange`, or `isAllowMetricFilterNameChange`; dashboard views use `permissions.isEnableCreateDashboardView`) | | `INVALID_ID` | The dashboard/embed ID does not belong to the token's Data App | Verify the ID and that the token was minted for the right Data App | | `UNAUTHORISED REQUEST!` | The request is missing a valid plugin token header | Ensure the embed component receives a `token` attribute | ## Metric execution errors (E1001–E1007) | Code | Message | Cause & fix | | ------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `E1001` | `Filter or Client variables detected in the query.` | The final SQL still contains an unresolved `{{…}}` token at execution. Causes: variable name doesn't match the filter's variable name (case-sensitive); the filter has no value or default; no matching filter is attached. Fix the name and give the filter a default value. See [Filter Troubleshooting](/guides/dashboards/filter-troubleshooting) | | `E1002` | `Metric data or query could not be found.` | The metric's stored query is missing — re-save the metric | | `E1003` | `Drill-down query execution failed.` | The drill-down query errored — check the underlying SQL | | `E1004` | `Invalid query or insufficient permissions to access it.` | The query failed validation or the caller lacks access | | `E1005` | `An error occurred while fetching data from the database.` | The data source returned an error — test the connection and run the SQL directly against the source | | `E1006` | `Forecast query execution failed.` | The forecast service errored on this metric | | `E1007` | `Hasura server error occurred while processing the request.` | Internal metadata-layer error — on self-hosted check the hasura service; on cloud contact support | Multi-select filter variables substitute as a parenthesized quoted list (e.g. `( 'US' , 'CA' )`). Write `WHERE col IN {{var}}` **without** your own parentheses — `IN ({{var}})` double-wraps into invalid SQL. ## Guest-token API errors (mint time) Returned by `POST /api/v2/guest-token/create`. See the [Guest Token reference](/developer-docs/helpers/api-reference/token) for the accepted payload. | Code | Meaning | | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | `AUTHENTICATION_ERROR` | Invalid or missing API key in the `Authorization` header | | `INVALID_REQUEST_BODY` | The body failed validation — includes any **unknown field** (`dataAppId`, `client_id`, `tenant_id`, `permissions.dashboards` are not valid fields) | | `INVALID_DATA_APP_NAME` | `dataAppName` doesn't match any Data App (case-sensitive) | | `CLIENT_ID_ERROR` | Invalid `clientId` value | | `WORKSPACE_ID_ERROR` | Workspace not found or inaccessible | | `DASHBOARD_PARAM_ERROR` / `EMBED_PARAM_ERROR` | Invalid dashboard/embed parameters | | `APP_FILTER_PARAM_ERROR` | Invalid `params.appFilters` shape | | `RLS_SETTINGS_PARAM_ERROR` | Invalid `params.rlsSettings` shape | | `DATASOURCE_NAME_ERROR` / `DATAMART_NAME_ERROR` | `datasourceName` / `datamartName` doesn't resolve | | `UNSUBSCRIBED_ACCOUNT_ERROR` | The account's subscription doesn't allow this operation | | `INTERNAL_SERVER_ERROR` | Server-side failure — retry, then contact support | ## Browser-side errors ### `QuotaExceededError … 'metric-data' exceeded the quota` The embed plugin caches metric data in `localStorage`, and a large metric blew past the browser's per-origin quota (\~5–10 MB). 1. Clear the key: `window.localStorage.removeItem('metric-data')` and reload. 2. Reduce the row/column count of the offending metric (`LIMIT`, pagination, or split it). This is a browser storage limit — it is unrelated to API rate limits, and the self-hosted `RATE_LIMIT` env var has no effect on it. ## Rate limiting (HTTP 429) Cloud API requests are throttled per Data App. Back off using the `Retry-After` header and cache read-heavy calls. See [Rate Limiting](/developer-docs/rate-limiting). # Security & Compliance Source: https://docs.usedatabrain.com/developer-docs/security How DataBrain keeps your data secure and helps you meet compliance requirements **At a Glance:** DataBrain uses bank-level AES-256 encryption, supports enterprise SSO and MFA, provides fine-grained access controls, and maintains SOC 2 Type II, ISO 27001, GDPR, and HIPAA compliance. DataBrain implements comprehensive security measures across every layer to protect your data, users, and platform. Security is built into our DNA so you can focus on building great analytics with confidence. For detailed security information, visit our [Security page](https://www.usedatabrain.com/security). *** ## Compliance & Certifications DataBrain Cloud is certified and compliant with major security and privacy standards: Compliance Certifications **Self-Hosted Deployments:** Compliance depends on your infrastructure configuration. DataBrain provides all the security features and controls needed to achieve these compliance standards. **Related Resources:** * [Security Overview](https://www.usedatabrain.com/security) * [Privacy Policy](https://www.usedatabrain.com/privacy) * [Cookie Policy](https://www.usedatabrain.com/cookie-policy) *** ## Data Protection ### Encryption - Bank-Level Security **Industry Standard:** We use the same AES-256 encryption used by banks and government agencies to protect your data. **Everything is encrypted when stored:** * User credentials and passwords (hashed and salted) * Database connection strings and credentials * API keys and authentication tokens * Dashboard and metric configurations * Audit logs and activity records Your data is encrypted on disk, in backups, and in our databases. Even if storage media is compromised, data remains protected. **All communications are encrypted:** * Login and authentication requests * Dashboard and metric data transfers * API requests and responses * File uploads and downloads * WebSocket connections for real-time updates We enforce HTTPS for all connections and use TLS 1.2 or higher with strong cipher suites. **Your passwords are never stored in plain text:** * One-way hashing using industry-standard algorithms * Unique salt per password (even identical passwords have different hashes) * Cannot be decrypted by anyone, including DataBrain staff * Password resets create new passwords rather than retrieving old ones This means your password is secure even if our database is compromised. ### Database Connection Security **All database connections are encrypted:** * PostgreSQL, MySQL, SQL Server with SSL/TLS * Snowflake and BigQuery (encrypted by default) * Redshift, Databricks, and all supported databases DataBrain automatically uses encrypted connections when available. **For maximum security on AWS:** * Direct private connection to your VPC * No public internet exposure required * Network-level isolation * Lower latency, higher security Your database doesn't need a public IP address with VPC peering. **Best practice for analytics:** * DataBrain only needs SELECT permissions * No risk of data modification * Access limited to specific schemas/tables * Easy to audit and revoke if needed Create a dedicated read-only database user for DataBrain. ### Multi-Tenant Data Isolation Complete data separation for SaaS applications and multi-client environments: Users see only their authorized data Applied automatically to all queries Complete separation by client ID **In a SaaS application:** 1. Generate guest token with unique client ID 2. DataBrain automatically filters all data by that client 3. Client A sees only Client A's data 4. Client B sees only Client B's data 5. Zero cross-client data access - complete isolation **No code changes required** - filtering happens automatically at the database level. **Fine-grained data access control:** * Filter data based on user attributes (role, department, region, etc.) * Applied automatically to all queries * Transparent to end users * Centrally managed and configured Perfect for hierarchical access (managers see team data, directors see department data, etc.) *** ## User Authentication Choose the authentication method that fits your security requirements: Traditional authentication with strong password policies and account protection Enterprise SSO with SAML, OIDC, Google Workspace, and Microsoft 365 Passwordless authentication via secure email codes Additional security layer with authenticator apps, SMS, or email ### Single Sign-On (SSO) Connect DataBrain with your existing identity provider for centralized user management: **Enterprise Identity Providers:** * Okta * Azure Active Directory * OneLogin * Auth0 * Any SAML 2.0 compliant provider Perfect for large organizations with existing identity infrastructure. **Modern OAuth 2.0 Providers:** * Keycloak * Google Workspace * Microsoft Identity Platform * Any OpenID Connect provider Simpler setup with JSON-based token format and better mobile support. **One-Click Sign-In:** * Google Workspace integration * Microsoft 365 connectivity * Azure AD support * Automatic user provisioning Quick setup with popular enterprise platforms. ### Multi-Factor Authentication (MFA) **Highly Recommended:** Enable MFA for all administrator accounts. MFA blocks 99.9% of automated attacks. **Time-based one-time passwords (TOTP):** * Google Authenticator * Microsoft Authenticator * Authy * Any TOTP-compatible app Works offline and can't be intercepted. **This is the most secure option.** **Receive verification codes via text:** * Works on any mobile phone * No app installation required * Good for occasional use More convenient but less secure than authenticator apps. **Get verification codes via email:** * No additional device required * Good for backup method * Delivered to your registered email Convenient option for secondary authentication. ### Session Management Automatic session security keeps your account protected: Sessions automatically refresh while you're active - no interruptions to your work. Automatic logout after 30 minutes of inactivity protects your account on shared devices. Stay logged in on trusted devices for up to 7 days (optional feature). **Important:** Don't use "Remember Me" on public or shared computers. View and manage active sessions across all your devices. Remotely log out from any device. *** ## Access Control & Permissions DataBrain uses role-based access control (RBAC) to ensure users have appropriate access: **Principle of Least Privilege:** Always grant the minimum permissions needed. Start with Viewer role and escalate only when necessary. ### User Roles **Perfect for:** Stakeholders, executives, business users **Can Do:** * View dashboards and metrics * Filter and explore data * Download reports and exports * Apply dashboard filters **Cannot Do:** * Create or edit content * Modify configurations * Manage users or settings Use this role for users who only need to view and analyze data. **Perfect for:** Data analysts, business analysts, content creators **Can Do:** * Everything Viewers can do, plus: * Create dashboards and metrics * Edit existing content * Configure visualizations * Write custom SQL queries * Share dashboards with teams **Cannot Do:** * Manage users or roles * Configure data sources * Access admin settings Use this role for users who create and maintain analytics content. **Perfect for:** IT administrators, security teams, platform managers **Can Do:** * Everything Editors can do, plus: * Manage users and assign roles * Configure data sources * Generate and manage API tokens * Configure SSO and security settings * Access audit logs * Set company-wide policies Use this role sparingly - only for users who need full platform control. ### Custom Roles Create custom roles for specific use cases: * **Department-specific access** - "Sales Analyst" role with sales dashboard access only * **Client-facing roles** - Limited viewer with export restrictions * **Temporary project access** - Time-limited elevated permissions * **Specialized workflows** - Custom permission combinations Document each custom role's purpose and regularly review assignments. **Follow these guidelines:** * Start with standard roles (Viewer, Editor, Admin) * Grant minimum necessary permissions * Review permissions quarterly * Remove inactive accounts after 30 days * Document custom role purposes * Test permission changes before deployment *** ## Token Management DataBrain uses secure tokens for API access and embedded analytics: **For Backend Integration** * Long-lived tokens for server applications * Scoped permissions (read, write, admin) * Production and test environments * Can be revoked instantly **For Embedded Dashboards** * Short-lived tokens for end users * Automatic client data filtering * Domain whitelisting * Usage tracking and analytics ### API Tokens **Security Critical:** Never expose API tokens in frontend code, GitHub, or client-side applications. Always generate tokens on your backend server. **Step-by-step process:** 1. Navigate to **Data Apps** → Select your app 2. Click **Generate API Token** 3. Set descriptive name (e.g., "Production Dashboard API") 4. Choose scopes (read, write, delete) 5. Set expiration date (recommended: 1 year) 6. **Copy token immediately** - it won't be shown again! 7. Store securely in password manager or secrets vault Use descriptive names like `prod-dashboard-2024` to track token purposes. **Grant only necessary permissions:** * **Read** - View dashboards and metrics (for embedding) * **Write** - Create and modify content (for integrations) * **Delete** - Remove resources (use sparingly) * **Admin** - Full access (only for administrative tools) Most embedding scenarios only need read permissions. **Keep your tokens secure:** * Store tokens in environment variables * Use separate tokens for dev/staging/production * Rotate tokens every 6 months * Revoke unused tokens immediately * Monitor token usage for anomalies * Never commit tokens to version control If a token is compromised, revoke it immediately and generate a new one. ### Guest Tokens For secure embedded analytics in customer-facing applications: **Built-in protection:** * **Domain Whitelisting** - Only works on approved domains * **Client Filtering** - Automatic data filtering by client ID * **Expiration Control** - Set time limits (recommended: 1 year with auto-renewal) * **Usage Tracking** - Monitor access for billing and security These features ensure each customer sees only their data. **Where to use guest tokens:** * Customer portals with personalized dashboards * Partner dashboards with specific metrics * Mobile app analytics integrations * Public reports on websites * Embedded analytics in SaaS applications Generate guest tokens on your backend, not in frontend JavaScript. **Restrict where dashboards can be embedded:** * Whitelist entries are **scheme-less** `host[:port]` — do not include `http://` or `https://` (the API rejects entries with a protocol) * Specify exact domains: `app.yourcompany.com` * Support subdomains: `*.yourcompany.com` (use carefully) * Include the port for local dev: `localhost:3000` * Never use wildcard `*` for all domains * Serve your embedding pages over HTTPS in production (the scheme just isn't part of the whitelist entry) The whitelist is stored account-wide — one list covers all your Data Apps. Even if someone steals your guest token, they can't use it on unauthorized domains. *** ## Platform Security ### API Protection Every API request is secured with multiple protection layers: All requests must be authenticated with valid tokens TLS 1.2+ encryption enforced for all connections Automatic protection against abuse and DDoS **Industry-standard HTTP security headers applied to all responses:** * **Strict-Transport-Security** - Forces HTTPS connections * **X-Frame-Options** - Prevents clickjacking attacks * **X-Content-Type-Options** - Prevents MIME type sniffing * **Content-Security-Policy** - Controls resource loading * **X-XSS-Protection** - Enables browser XSS filters These headers provide defense-in-depth protection against common web vulnerabilities. **Protects against abuse and ensures fair usage:** | Request Type | Time Window | Limit | | ------------------------ | ----------- | ------------ | | **Login/Authentication** | 1 minute | 30 requests | | **General API Calls** | 2 minutes | 500 requests | | **Data Queries** | 2 minutes | 500 requests | Need higher limits for your use case? Contact support to discuss custom rate limits. **Complete visibility into system activity:** **What's logged:** * User login/logout events * Permission changes * Data access patterns * API token usage * Configuration changes * Failed authentication attempts **Benefits:** * Security monitoring and threat detection * Compliance and audit requirements * Troubleshooting and debugging * Usage analytics Only administrators can access audit logs via Settings → Audit Logs. *** ## Embedded Analytics Security Secure your embedded dashboards with built-in protection: ### Domain Whitelisting **Critical Security Control:** Always restrict which domains can embed your dashboards. Never use wildcard `*` for all domains. **How to configure:** 1. Specify exact allowed domains in guest token settings 2. Use HTTPS only (never HTTP in production) 3. Be specific - avoid broad wildcards when possible **Examples:** * **Good:** `https://app.yourcompany.com` * **Good:** `https://dashboard.yourcompany.com` * **Use carefully:** `https://*.yourcompany.com` (all subdomains) * **Never:** `*` (all domains) Test your configuration: Approved domains should load dashboards, unauthorized domains should be blocked. ### Client Data Isolation Automatic data separation for multi-tenant applications: **Complete data isolation in 4 simple steps:** 1. **Generate guest token** with unique client ID on your backend 2. **Embed dashboard** in your application with that token 3. **DataBrain filters** all data automatically by client ID 4. **Client sees only their data** - zero cross-client access Zero configuration needed - filtering happens automatically at the database level. **Why automatic client filtering matters:** * No manual filtering code needed * Impossible to bypass (enforced at database level) * Works across all queries automatically * Scales to thousands of clients * Complete data isolation guaranteed Perfect for SaaS applications where each customer needs isolated data. *** ## Self-Hosted Security Additional security measures for self-hosted deployments: **Your Responsibility:** For self-hosted installations, you're responsible for infrastructure security. Follow these best practices to maintain a secure deployment. **Secure your server infrastructure:** * Keep OS and software updated with latest security patches * Configure firewall rules (allow only necessary ports) * Disable unnecessary services and features * Use SSH key authentication (disable password auth) * Implement fail2ban to block brute force attempts * Set up automatic security updates * Use strong, unique passwords for all accounts Run security audits quarterly to identify vulnerabilities. **Enforce encrypted connections:** * Use valid certificates from trusted CA (Let's Encrypt is free) * Enable automatic certificate renewal * Support TLS 1.2 or higher only * Disable weak cipher suites * Enable HSTS header * Test SSL configuration regularly Never use self-signed certificates in production. **Protect your database:** * Use strong, unique passwords (20+ characters) * Enable SSL/TLS for all connections * Limit network access (whitelist IPs only) * Use read-only credentials for DataBrain * Encrypt data at rest * Set up automated daily backups * Test backup restoration monthly Store database backups in a separate location from primary database. **Stay informed about security events:** **System Monitoring:** * CPU, memory, and disk usage * Network traffic patterns * Application error rates * Service health checks **Security Monitoring:** * Failed login attempts * Unusual access patterns * Configuration changes * Certificate expiration Set up email/SMS alerts for critical events. **Implement reliable backups:** **What to backup:** * Database (all data) * Application files and configurations * User uploads and assets * SSL certificates **Backup schedule:** * Full backup: Weekly * Incremental: Daily * Test restores: Monthly **Storage:** * Encrypt all backups * Store off-site (different location/region) * Retain for 30+ days * Document restore procedures *** ## Related Documentation Learn how to generate secure guest tokens for embedded analytics Enhanced security by managing tokens on your backend server Implement complete data isolation for multi-tenant applications Complete API reference with authentication examples *** ## Additional Resources Comprehensive security information and certifications How we collect, use, and protect your personal data Information about our use of cookies and tracking technologies *** ## Need Help? Contact DataBrain support for security assistance or to report security vulnerabilities Reach out to discuss SOC 2, HIPAA, GDPR, or other compliance requirements *** **Last Updated:** December 2025 | **Version:** 2.0 # Self Hosted Config Source: https://docs.usedatabrain.com/developer-docs/self-hosted-config When self hosted version of the app is used, the app needs to use these settings during embedding. To change the configs we need to add some changes - Where we are importing the plugin in the same file - ```js theme={"dark"} import "@databrainhq/plugin/web"; window.dbn = { baseUrl: SELFHOSTED_URL, }; ``` Assign configs in the `window.dbn` object. baseUrl - The base API endpoint e.g. [https://api.example.com](https://api.example.com), [https://yourdomain.com](https://yourdomain.com), etc. You may face typescript errors while assigning to `window.dbn` this can be resolved by adding the below code to any global `d.ts` file ```ts theme={"dark"} interface Window { dbn: Record; } ``` # Self-Hosted Health Checks & Probes Source: https://docs.usedatabrain.com/developer-docs/self-hosted-health-checks How to configure liveness/readiness probes and health checks for self-hosted Databrain (Kubernetes and Docker), including graceful shutdown (SIGTERM) behavior. Self-hosted Databrain exposes built-in health endpoints that you can use for Kubernetes probes, Docker health checks, and external monitoring. This guide explains: * **Which endpoints to use** * **How to configure liveness and readiness probes** (Kubernetes) * **How to configure Docker health checks** * **How graceful shutdown (SIGTERM) works** in the backend and forecast services This is a **DevOps configuration guide**, not an API reference. *** ## Health endpoints overview Databrain services expose simple JSON health endpoints: * **Backend (Express API)** – default port `3000` * `GET /health/live` – liveness * `GET /health/ready` – readiness (checks Hasura, Postgres via Hasura, and Keycloak if configured) * **Forecast service (FastAPI)** – default port `8082` * `GET /health/live` * `GET /health/ready` * **Hasura** * `GET /healthz` – built-in Hasura health * **App (frontend)** * `GET /` – static app root > For self-hosted deployments, replace host and ports with your actual values. If you run the backend behind a prefix (e.g. `/api`), the health paths become `/api/health/live` and `/api/health/ready`. *** ## Kubernetes configuration This section shows typical probe configuration for a **Kubernetes** deployment. Adjust ports and paths to match your manifests. ### Hasura deployment Use the built-in `/healthz` endpoint for both liveness and readiness: ```yaml theme={"dark"} livenessProbe: httpGet: path: /healthz port: 8082 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: /healthz port: 8082 initialDelaySeconds: 5 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 ``` > Note: the backend uses Hasura’s `healthz?strict=true` internally when evaluating Postgres health. **Do not** add query strings like `?strict=true` directly to Kubernetes `httpGet` probes – some Kubernetes versions URL-encode `?` which can break routing. Use plain `/healthz` in the probe and rely on the backend’s `/health/ready` for strict DB checks. ### Backend deployment (Express API) The backend mounts health endpoints at `/health`. Recommended probes: ```yaml theme={"dark"} livenessProbe: httpGet: path: /health/live port: 3000 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: /health/ready port: 3000 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 terminationGracePeriodSeconds: 35 ``` * **Liveness (`/health/live`)** * Returns `{ "status": "live" }` with HTTP 200 when the process is running. * Does **not** perform dependency checks. * **Readiness (`/health/ready`)** * Returns HTTP 200 and `{ "status": "ready", "checks": { ... } }` when: * Hasura is reachable (`/healthz`) * Postgres is healthy via Hasura strict health * Keycloak is healthy (if configured) * Returns HTTP 503 and `{ "status": "not_ready", "checks": { ... } }` when any check is failing. ### Forecast deployment (FastAPI) The forecast service is a separate FastAPI app with its own health endpoints: ```yaml theme={"dark"} livenessProbe: httpGet: path: /health/live port: 8082 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 readinessProbe: httpGet: path: /health/ready port: 8082 initialDelaySeconds: 20 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 terminationGracePeriodSeconds: 35 ``` * `GET /health/live` returns `{ "status": "live" }`. * `GET /health/ready` returns `{ "status": "ready" }` when the app is initialized and can accept requests. ### App deployment (frontend) For the frontend container, it’s usually enough to probe the root URL: ```yaml theme={"dark"} livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 ``` *** ## Docker / Docker Compose health checks For non-Kubernetes self-hosted setups, use Docker health checks with the same endpoints. ### Backend (Express API) ```yaml theme={"dark"} services: backend: image: your-backend-image ports: - "3000:3000" healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost:3000/health/ready || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 20s stop_grace_period: 35s ``` ### Forecast service (FastAPI) ```yaml theme={"dark"} services: forecast: image: your-forecast-image ports: - "8082:8082" healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost:8082/health/ready || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 20s stop_grace_period: 35s ``` ### Hasura ```yaml theme={"dark"} services: hasura: image: hasura/graphql-engine ports: - "8082:8080" healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost:8080/healthz || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 20s ``` ### App (frontend) ```yaml theme={"dark"} services: app: image: your-frontend-image ports: - "80:80" healthcheck: test: ["CMD-SHELL", "curl -fsS http://localhost/ || exit 1"] interval: 10s timeout: 3s retries: 3 start_period: 20s ``` *** ## Graceful shutdown & SIGTERM behavior Recent backend changes added **graceful shutdown** handling for the Express API and improved lifecycle hooks for the forecast service. ### Backend (Express API) Behavior (from `serverless/express/src/index.ts`): * On `SIGTERM` or `SIGINT`: * Logs: ` signal received: closing HTTP server`. * Calls `server.close()`: * Stops accepting new connections. * Allows in-flight requests to complete. * When the server is closed: * Logs `HTTP server closed`. * Calls `process.exit(0)`. * A 30-second timeout is started: * If shutdown is not complete within 30 seconds: * Logs `Could not close connections in time, forcefully shutting down`. * Calls `process.exit(1)`. **Kubernetes recommendation** * Set `terminationGracePeriodSeconds` to at least **35 seconds** for the backend pod. * This gives the app enough time to drain connections and exit cleanly after receiving `SIGTERM`. ### Forecast service (FastAPI) Behavior (from `forecast-timeseries/api.py`): * Uses a FastAPI `lifespan` context manager: * On startup: prints `Starting up Forecast service...`. * On shutdown: prints `Shutting down Forecast service...`. * This is where you can extend logic to close external resources (LLM clients, DB connections, etc.). **Kubernetes / Docker** * Use the same `terminationGracePeriodSeconds` / `stop_grace_period` (35s) pattern as the backend. *** ## Summary * Use `/health/live` for **liveness**, `/health/ready` for **readiness**. * For strict database checks, rely on the backend’s `/health/ready`, which already queries Hasura and Postgres. * Configure Kubernetes and Docker health checks against these endpoints. * Ensure termination grace periods are **≥ 35s** so graceful shutdown on `SIGTERM` can complete without forced kills. # Dashboard for Multiple Clients Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/dashboard-for-multiple-clients One universal dynamic dashboard for multiple clients 1. **Set up multi-data source workspace with one universal dynamic dashboard** Kindly refer the below link: 2. **Embedding** When embedding the dashboard for a client: * Generate a **guest token** via DataBrain’s API. * Pass the client's unique ID in the token payload. * DataBrain will automatically scope all metric queries based on the passed Client ID. To obtain a guest token from DataBrain, utilize our REST API from your backend system. ### Cloud version: ```bash theme={"dark"} Post: ``` ### Self-hosted version: ```bash theme={"dark"} Post: /api/v2/guest-token/create ``` ### Simple Request Body: ```json theme={"dark"} { "clientId": "id", // "None" if no tenancy available "dataAppName": "dataappname", "datasourceName": "data source name" // only for multi-datasource embed setup } ``` This ensures that the same dashboard shows different, correct data for each client — securely and efficiently. # Dashboards for Client Groups Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/dashboards-for-client-group Segmenting Dashboards based on user accounts/client groups. ### 1.Client Table with Groups Each client\_id is associated with a client\_group. Based on the group, they will be served a specific dashboard. | client\_id | client\_group | | ---------- | ------------- | | 1 | Group A | | 2 | Group B | | 3 | Group C | | 4 | Group A | | 5 | Group B | | 6 | Group C | | 7 | Group A | | 8 | Group B | | 9 | Group C | | 10 | Group A | *Note: The above table is a representation of the client organization table maintained on your database.* ### Implementation Outline: 1. **Master Dashboard**: Create a Master Dashboard containing all metrics. 2. **Client Dashboards**: For each client group, create separate dashboards that pull metrics from the Master Dashboard. 3. **Automatic Sync**: Updates in the Master Dashboard reflect in all client dashboards using those metrics. 4. **Embedding**: Embed each Client Group Dashboard to display only the relevant metrics per group. ### 2. Dashboard IDs by Client Group Define IDs for each dashboard corresponding to the client groups. ```js theme={"dark"} const dashboardIds = { "Group A": "dashboard-id-a", "Group B": "dashboard-id-b", "Group C": "dashboard-id-c" }; // Function to fetch dashboard ID based on client group function getDashboardId(clientGroup) { return dashboardIds[clientGroup]; } ``` ## Generate Token To obtain a guest token from DataBrain, utilize our REST API from your backend system. ```bash theme={"dark"} POST: https://api.usedatabrain.com/api/v2/guest-token/create ``` **Simple Request Body:** ```json theme={"dark"} { "clientId": "id", "dataAppName": "dataappname" } ``` ### 3. Embedding the Dashboard This function uses the fetched token and dashboard ID for the appropriate client group to embed the dashboard. ```javascript theme={"dark"} function embedDashboard(clientGroup, token) { const dashboardId = getDashboardId(clientGroup); return ( `` ); } ``` ### Summary This consolidated approach uses the `client_id` and `client_group` table to control access to specific dashboards. One token for all dashboards and you change the `dashboard-id` based on `clientGroup`. # Embedding: Role based Dashboard Filtering Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/embedding-role-based-dashboard-filtering Dashboard Filtered based on the user role. **Create a Dashboard Filter** * In your dashboard, create a new ‘Dashboard Filter’. * In the "Apply On" section, enable the App Filter option. **Passing from Guest Token** * You can link a guest token here to pass the filter values dynamically. Refer the below document to generate a guest token. ℹ️ Token Below is a sample payload structure: ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { "name": "Eric", "country": ["USA", "CANADA"], "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-03-23" }, "price": { "min": 1000, "max": 5000 } }, "isShowOnUrl": true } ] } } ``` Make sure the options and values match the data type of the filter for successful integration. ### Example Use Case: Let’s assume you have three roles: * Admin * Editor * Viewer And two Dashboard Filters: * `Country: ["USA", "CANADA", "MEXICO", "CHINA", "INDIA"]` * `Company: ["ALPHABET", "GOOGLE", "APPLE"]` And below is the access level of each role:
Role/Dashboard Filters Company Country
Admin All Companies All Countries
Editor All Companies USA, CANADA, MEXICO
Viewer Alphabet USA
Now using the information from the table above, you can input the values to generate a guest token according to the specified role. **Guest token for Admin:** ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { "client": ["ALPHABET", "GOOGLE", "APPLE"], "country": ["USA", "CANADA", "MEXICO", "CHINA", "INDIA"] }, "isShowOnUrl": true } ] } } ``` **Guest token for Editor:** ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { "client": ["ALPHABET","GOOGLE","APPLE"], "country": ["USA","CANADA","MEXICO"] }, "isShowOnUrl": true } ] } } ``` **Guest token for Viewer:** ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { "client": ["ALPHABET"], "country": ["USA"] }, "isShowOnUrl": true } ] } } ``` ### Optimizing Large Filters with SQL integration For filters involving a large number of options (e.g., over 500), manually passing all values becomes inefficient. By integrating SQL, you can dynamically fetch options from your database, simplifying the process and improving efficiency. The SQL query specified under the "sql" key dynamically fetches the latest values from the specified database table. ### Example Configuration Let’s modify the earlier example for Admin to demonstrate SQL integration for dynamically fetching filter options: **Guest token for Admin with SQL Integration:** ```json theme={"dark"} { "clientId": "id", "workspaceName": "workspacename", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { "client": { "sql": "SELECT \"name\" FROM \"public\".\"companies\" WHERE \"role\"='admin' ", "columnName": "name" }, "country": { "sql": "SELECT \"name\" FROM \"public\".\"countries\" WHERE isEnabled=true", "columnName": "name" } }, "isShowOnUrl": true } ] } } ``` ### Key Benefits 1. **Dynamic Updates:** The SQL query retrieves only the latest relevant options from your database. * Example: `SELECT "name" FROM "public"."countries" WHERE isEnabled=true` fetches active country names. 2. **Efficiency:** Eliminates the need to manually manage large datasets in the configuration. 3. **Flexibility:** The `columnName` specifies the field in the query result to use as filter values. 4. **Scalability:** Handles thousands of options seamlessly, reducing payload size and improving performance. ### Ideal Use Case This approach ensures that filters remain efficient, scalable, and user-friendly, with minimal manual effort to keep options up to date. # Timezone Handling in Guest Token Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/guest-token-timezone Pass a timezone parameter when generating a guest token to ensure SQL queries run in the correct timezone and date/time fields are consistently formatted across regions. ## Overview Databrain allows you to pass a **timezone parameter (`params.timezone`)** while generating a guest token. This ensures that: * SQL queries are executed in the correct timezone * Date/time fields are consistently formatted * Dashboard users across regions see accurate time-based insights ## Supported Data Sources Timezone-aware execution is supported for: * Clickhouse * Trino * Redshift * CockroachDB * Postgres * MSSQL ## What is `params.timezone`? ``` params.timezone -- string ``` * Accepts a valid IANA timezone string * Sets the database session timezone * Ensures all date/time operations respect the specified timezone ## Common Timezone Values | Timezone | Description | | :---------------------- | :------------------------- | | `"UTC"` | Coordinated Universal Time | | `"America/New_York"` | Eastern Time (US) | | `"America/Los_Angeles"` | Pacific Time (US) | | `"Europe/London"` | GMT / BST | | `"Asia/Kolkata"` | Indian Standard Time | | `"Australia/Sydney"` | Australian Eastern Time | ## Guest Token Example with Timezone ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "timezone": "America/New_York" } } ``` ## Step-by-Step Implementation Create the required resources via the following APIs: * [Create DataApp](/developer-docs/helpers/api-reference/create-data-app) * [Create API Token for corresponding DataApp](/developer-docs/helpers/api-reference/create-api-token) Ensure your dataset contains a timestamp column. Create a Datamart using the [Create Datamart API](/developer-docs/helpers/api-reference/create-datamart) and specify [isApplyTimezone](/developer-docs/helpers/api-reference/create-datamart#isApplyTimezone). Create an Embed using your created datamart via the [Create Embed API](/developer-docs/helpers/api-reference/create-dashboard-embed) inside the created DataApp. Include the `params.timezone` field in your payload when calling the [Guest Token API](/developer-docs/helpers/api-reference/token). ```json theme={"dark"} { "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "timezone": "America/New_York" } } ``` Use an appropriate IANA timezone (e.g., `"Asia/Kolkata"`). Open your **demo link**, click **+ Create Metric**, and drag and drop the **date column** into the chart. Then: 1. Open **Browser DevTools → Network Tab** 2. Inspect the executed query Verify: * The timezone value is applied in the query/session * `"timezone": ""` is present inside the request payload (`params`) ## How It Works Internally The timezone is applied at the database session level. Queries run as if the database is operating in that timezone. Functions like `NOW()`, `DATE_TRUNC`, and `TIMESTAMP` conversions will all respect the passed timezone. # Localized Currency Symbols Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/localized-currency-symbols This guide provides a practical approach for utilizing Dynamic Property to dynamically display revenue in multiple currencies for different countries. ### Use Case: Representing Revenue in Different Countries An e-commerce business operating in multiple countries needs to represent revenue in different currencies. The finance team chooses to analyze revenue trends in localized formats by selecting different countries. Here are the steps to implement Dynamic Property for revenue tracking: ### 1. Access Dynamic Property: * In the metric creation page, click on `"[X]"` icon near the sort icon. * This will open the **"Dynamic Property"** panel on the right side of the screen. * Then, click on **"+Property"** to add a dynamic property to your metric. ### 2. Configure Dynamic Property: * Enter the Property Name and choose between the two Property Types: * **"Auto"** * Choose the dataset and the column you want to consider. * **"Custom"** * Enter your SQL query to choose your dynamic value and dependent columns, and select the column name. * In this example, we select the column containing **currency codes** or create a **custom query** and save it as `[[Units]]`. * Then, select the dependencies: dashboard or metric filter type. (Optional) * Click **"Create"** to save the property. ### 3. Verify Property Creation * Check the property listed in the Dynamic Property panel. * Copy the property name format: \[\[Units]] and close the panel. ### 4. Configure formatting options: * In the Formatting Section, set the prefix as \[\[Units]] * This ensures that revenue values in the **Y-axis** display the correct currency code dynamically. ### 5. Save metric to Dashboard * Click the **"Save to Dashboard"** button. * Then, use `[[Units]]` in: * **Metric Title** * **Metric Description** * **Metric Long Description**, and * **Footnote** ### 6. Verify Dynamic Property Functionality #### Metric Filter Example: The `[[Units]]` dynamic property updates the **currency unit** based on the **selected country** in the **metric filter**. ### Dashboard Filter Example: The `[[Units]]` dynamic property updates the **currency unit** based on the **selected country** in the **dashboard filter**. Please refer the below link on how to create Dynamic Property: This guide explains the process of using dynamic properties in metric creation. These properties can fetch dynamic values directly from the database, with dependencies on dashboard or metric filters. # Manage Metrics Source: https://docs.usedatabrain.com/developer-docs/solutions-alchemy/manage-metrics Allow end user to manage metrics from embedded dashboard. **Manage Metrics changes are per-dashboard, not per-viewer.** If multiple customers share the same embedded dashboard, one customer unchecking a metric hides it for **every** customer viewing that dashboard. Only enable Manage Metrics for end users on shared dashboards if that is acceptable — for per-customer metric selection, give each customer their own dashboard using the master + client dashboards pattern in the [Tenancy Model](/developer-docs/tenancy-model#master--client-dashboards-pattern). By Default, all metrics are marked as mandatory to dashboard, to allow end user to archive metric from dashboard, mark the allowed metric on Save to Dashboard form & save it. allow end user to archive metric Enable Manage Metric for end user from **Workspace Settings** End user can archive/unarchive metrics from manage metric in embedded dashboard settings # Tenancy Model Source: https://docs.usedatabrain.com/developer-docs/tenancy-model How DataBrain enforces tenant isolation: Workspace vs Datamart vs Data App vs Client Group, guest-token variables, Manage Metrics scope, and the master + client dashboards pattern. This is the single reference for how DataBrain enforces tenant isolation and metric visibility when you embed dashboards in a multi-tenant application. ## Concepts, top-down * **Workspace** — outermost container. Holds Data Sources, Datamarts, Data Apps, Dashboards, Metrics. Members and permissions are Workspace-scoped. Most teams run one Workspace. * **Data Source** — connection to your warehouse. Credentials live here. * **Datamart** — logical selection of tables, columns, relationships, and joins on top of a Data Source. This is where the **Client ID column** for tenant isolation is set, and where the semantic layer lives. * **Data App** — the unit of embedding. Carries the API key that authenticates guest-token minting and the reference to its Datamart. One Data App per embedding surface — you do **not** need a Data App per tenant. * **Client Group** — a logical grouping of end-tenants that share a dashboard structure. * **Manage Metrics** — a per-dashboard toggle that lets users pick which metrics appear. See the gotcha below before relying on it. ## The tenant identifier: three names, three places | Name | Where | What it is | | ---------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `clientId` | Guest-token JSON payload | Supplies the tenant value for the session. The only accepted spelling — `client_id` and `tenant_id` are rejected | | `'client_id_variable'` | Custom metric SQL | A **bare quoted token** (no curly braces) substituted with the session's tenant value at query time, e.g. `WHERE client_column = 'client_id_variable'` | | `{{DATABASE_NAME}}` | Custom metric SQL | The only curly-brace tenancy variable — resolves to the tenant's database/schema for database-per-tenant setups | ## Tenant-isolation strategies ### 1. Row-per-tenant (client\_id column) All tenants share tables; every table has a tenant column. Configure the Datamart's Client ID column mapping. How the filter is applied depends on the metric type: * **Builder (visual/dataset) metrics:** DataBrain auto-injects the tenant filter into the query. Do not add your own. * **Custom SQL metrics:** the filter is **not auto-injected**. You must write it yourself: ```sql theme={"dark"} SELECT * FROM orders WHERE client_id = 'client_id_variable' ``` A custom SQL metric that omits the tenant filter runs **unscoped** and returns every tenant's rows. Always include `'client_id_variable'` in custom SQL when your Datamart uses table-level tenancy. ### 2. Schema- or database-per-tenant Each tenant has its own schema/database. Reference it in metric SQL via `{{DATABASE_NAME}}`, which resolves from the guest token's `clientId` through the Datamart mapping. ### Anti-pattern: hard-coded tenant IDs Never save a literal tenant id in metric SQL (`WHERE client_id = 'acme'`) — for example by saving a metric while previewing as a specific client. That literal ships to **every** viewer and has caused real cross-tenant data leaks. If a metric must be scoped to one tenant on purpose, use RLS or an App Filter in the guest token instead. ## Manage Metrics scope — the important gotcha **Manage Metrics visibility is per-dashboard, not per-viewer.** If Customer A unchecks a metric on a shared dashboard, it disappears for Customer B too. That is by design — do not use Manage Metrics for per-tenant metric visibility. Use the pattern below instead. ## Master + client dashboards pattern For "each customer picks their own metric subset from a shared library": 1. Create one **master dashboard** with every metric in the library. 2. For each customer (or Client Group), create a **client dashboard** derived from the master — its own layout and visible-metric subset. 3. Embed the client dashboard per tenant with that tenant's `clientId` in the guest token. Client dashboards can be provisioned programmatically — via the [Import Dashboard API](/developer-docs/helpers/api-reference/import-dashboard) or the MCP server's `create_embed` tool (which can clone a `templateDashboardId` per client). Note that import/clone is a **copy** operation: later edits to the master do not propagate to already-created client dashboards. ## Row-level security (RLS) RLS (`params.rlsSettings` in the guest token) is an additional per-session constraint **on top of** tenant isolation — for example `region = 'NA'` for one user. It is enforced server-side and invisible to the end user. Do not use RLS as a substitute for the Datamart's Client ID mapping. ## Client selector Embedded dashboards never render a client selector — the tenant is fixed by the guest token's `clientId`. The client/database dropdown you see inside the DataBrain app is for workspace members previewing data as different clients; it is not part of the embed. ## Where each setting lives | Setting | Where | Scope | | --------------------------------------- | ----------------------------- | ----------------------------------------- | | Client ID column mapping | Datamart | Per Datamart | | Data App API key | Data App | Per Data App | | Whitelist Domains | Edited from Data App settings | Account-wide (one list for all Data Apps) | | `clientId`, `rlsSettings`, `appFilters` | Guest token payload | Per session | | Manage Metrics toggle | Dashboard settings | Per dashboard, shared across viewers | | Client Group membership | Workspace settings | Per tenant grouping | ## Related * [Guest Token](/developer-docs/helpers/api-reference/token) * [Multi-Tenant Access Control](/developer-docs/multi-tenant-access-control) * [Error Codes Reference](/developer-docs/reference/error-codes) # Troubleshooting Guide Source: https://docs.usedatabrain.com/developer-docs/testing/troubleshooting Common issues and solutions for embedded DataBrain dashboards This guide covers common issues you might encounter when embedding DataBrain and how to resolve them. ## Quick Diagnostics Checklist Before diving into specific issues, run through this checklist: Open Developer Tools (F12) and look for errors in the Console tab Check the Network tab for failed API calls or 401/403 errors Ensure your guest token is valid and not expired Double-check dashboard-id and metric-id values Try the sample token/dashboard to isolate the issue ## Common Issues ### Dashboard Not Rendering **Symptoms:** * Empty space where dashboard should be * No errors in console * Component seems to load but shows nothing **Solutions:** 1. **Ensure plugin is imported before rendering:** ```javascript theme={"dark"} // ✅ Correct - import first import '@databrainhq/plugin/web'; import Dashboard from './Dashboard'; // ❌ Wrong - import after component import Dashboard from './Dashboard'; import '@databrainhq/plugin/web'; ``` 2. **Check for web component support:** ```javascript theme={"dark"} // Add this check if (!customElements.get('dbn-dashboard')) { console.error('DataBrain web components not loaded'); } ``` 3. **Verify container has height:** ```css theme={"dark"} .dashboard-container { min-height: 600px; /* or 100vh */ } ``` 4. **Check z-index conflicts:** ```css theme={"dark"} dbn-dashboard { position: relative; z-index: 1; } ``` **Symptoms:** * Dashboard appears briefly then vanishes * May happen on route changes or re-renders **Solutions:** 1. **React: Prevent re-renders destroying the component:** ```javascript theme={"dark"} import { useRef, useEffect } from 'react'; function Dashboard({ token }) { const dashboardRef = useRef(null); useEffect(() => { if (dashboardRef.current && token) { dashboardRef.current.setAttribute('token', token); } }, [token]); return ( ); } ``` 2. **Vue: Use v-show instead of v-if:** ```vue theme={"dark"} ``` 3. **Check for parent component unmounting:** Add key prop to prevent recreation ```javascript theme={"dark"} ``` **Symptoms:** * Loading spinner never stops * Dashboard never renders **Causes & Solutions:** 1. **Invalid token:** ```javascript theme={"dark"} // Check token format console.log('Token:', token); // Should be a UUID like: 3affda8b-7bd4-4a88-9687-105a94cfffab ``` 2. **Wrong dashboard ID:** ```javascript theme={"dark"} // Verify dashboard-id console.log('Dashboard ID:', dashboardId); // Should match ID from Data App ``` 3. **Network blocked:** * Check browser extensions (ad blockers, privacy tools) * Verify no corporate firewall blocking * Check CORS settings ### Authentication & Token Errors Each token error string has exactly one meaning: `INVALID_TOKEN` = token not found in this deployment (usually a cloud vs self-hosted mismatch, or the embed isn't receiving the minted value); `TOKEN_EXPIRED` = past its `expiryTime`; `UNAUTHORIZED_ORIGIN` = origin not on Whitelist Domains; `UNAUTHORIZED` = the token isn't allowed this request — `allowedEmbeds` miss, wrong Data App/workspace, or (for dashboard-filter/view requests) that permission isn't enabled. Guest tokens are database-backed UUIDs — there is no signing secret. Full table: [Error Codes Reference](/developer-docs/reference/error-codes). **Symptoms:** * Error: "API key is invalid or expired" * 401 status in network tab **Solutions:** 1. **Verify API token is correct:** ```bash theme={"dark"} # Test API token curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer YOUR_API_TOKEN' \ --header 'Content-Type: application/json' \ --data '{"clientId":"test","dataAppName":"your-app"}' ``` 2. **Ensure Bearer prefix:** ```javascript theme={"dark"} // ✅ Correct headers: { 'Authorization': `Bearer ${apiToken}` } // ❌ Wrong headers: { 'Authorization': apiToken } ``` 3. **Regenerate API token:** * Go to Data App settings * Generate new API token * Update environment variables **Symptoms:** * "Token has expired" message * Dashboard stops working after some time **Solutions:** 1. **Set appropriate expiry time:** ```javascript theme={"dark"} // Backend token generation { clientId: userId, dataAppName: 'your-app', expiryTime: 3600000 // 1 hour (adjust as needed) } ``` 2. **Implement token refresh:** ```javascript theme={"dark"} import { useEffect, useState, useCallback } from 'react'; function useDataBrainToken() { const [token, setToken] = useState(null); const refreshToken = useCallback(async () => { const response = await fetch('/api/databrain/guest-token'); const data = await response.json(); setToken(data.token); }, []); useEffect(() => { refreshToken(); // Refresh token every 50 minutes (if set to 1 hour expiry) const interval = setInterval(refreshToken, 50 * 60 * 1000); return () => clearInterval(interval); }, [refreshToken]); return token; } ``` 3. **Handle token expiry event:** ```javascript theme={"dark"} window.handleTokenExpiry = async (event) => { if (event.type === 'TOKEN_EXPIRED') { const newToken = await fetchFreshToken(); // Update token in component document.querySelector('dbn-dashboard') .setAttribute('token', newToken); } }; ``` **Symptoms:** * "Access to fetch blocked by CORS policy" * Cross-origin errors in console **Solutions:** 1. **Generate tokens from backend (not frontend):** ```javascript theme={"dark"} // ✅ Correct - backend generates token // backend/api/token.js const token = await generateGuestToken(userId); // ❌ Wrong - frontend trying to generate // Causes CORS errors fetch('https://api.usedatabrain.com/api/v2/guest-token/create') ``` 2. **Whitelist your domain:** * Go to your Data App's settings → **Whitelist Domains** (the input field there is labeled "Allowed Origins" — same setting) * Add your domains as scheme-less `host[:port]` entries, e.g. `app.yoursite.com` or `localhost:3000` — do not include `http://` or `https://` * Wildcards like `*.yoursite.com` are supported * Include all environments (dev, staging, prod) * Note: the whitelist applies account-wide — the same list covers all your Data Apps 3. **Check for mixed content (HTTP/HTTPS):** ```javascript theme={"dark"} // Ensure HTTPS if embedding on HTTPS site const apiUrl = window.location.protocol === 'https:' ? 'https://api.usedatabrain.com' : 'http://api.usedatabrain.com'; ``` ### Display & Styling Issues **Symptoms:** * Dashboard hidden behind other elements * Modals or dropdowns don't appear correctly **Solutions:** 1. **Set appropriate z-index:** ```css theme={"dark"} dbn-dashboard { position: relative; z-index: 10; } /* If dashboard needs to be on top */ dbn-dashboard::part(modal) { z-index: 9999; } ``` 2. **Check parent container:** ```css theme={"dark"} .dashboard-container { position: relative; z-index: auto; /* Don't create new stacking context */ } ``` 3. **Use isolation:** ```css theme={"dark"} .dashboard-wrapper { isolation: isolate; } ``` **Symptoms:** * Dashboard doesn't fit screen * Charts overlap on mobile * Scrolling issues **Solutions:** 1. **Ensure container is responsive:** ```css theme={"dark"} .dashboard-container { width: 100%; max-width: 100vw; min-height: 600px; overflow: auto; } @media (max-width: 768px) { .dashboard-container { min-height: 400px; } } ``` 2. **Set viewport meta tag:** ```html theme={"dark"} ``` 3. **Use responsive theme:** ```javascript theme={"dark"} const theme = { general: { primaryColor: '#0066CC' }, responsive: { breakpoints: { mobile: 768, tablet: 1024 } } }; ``` **Symptoms:** * Custom colors not showing * Font changes not working * Theme options ignored **Solutions:** 1. **Stringify theme object:** ```javascript theme={"dark"} // ✅ Correct // ❌ Wrong ``` 2. **Check theme structure:** ```javascript theme={"dark"} const theme = { general: { primaryColor: '#0066CC', backgroundColor: '#FFFFFF', fontFamily: 'Inter, sans-serif' }, chart: { colors: ['#0066CC', '#00C2B8'] // Array of colors } }; ``` 3. **Verify CSS specificity:** ```css theme={"dark"} /* Your styles might be overriding */ dbn-dashboard { all: initial; /* Reset if needed */ } ``` ### Performance Issues **Symptoms:** * Dashboard takes long to load * Metrics render slowly * Poor performance with large datasets **Solutions:** 1. **Enable caching in workspace settings:** * Go to **Workspace Settings → Cache Settings** * Enable query result caching * Set an appropriate TTL (start with 3600 seconds / 1 hour) * Choose **DataBrain Caching** for quick setup, or **BYOC** if you have your own Redis * See the [Cache Settings guide](/guides/onboarding-and-configuration/workspace-settings/cache-settings) for detailed setup 2. **Apply filters to limit data:** ```javascript theme={"dark"} const tokenRequest = { clientId: userId, dataAppName: 'your-app', params: { dashboardAppFilters: [{ dashboardId: 'dashboard-id', values: { date_range: { startDate: '2024-01-01', endDate: '2024-03-31' } } }] } }; ``` 3. **Optimize metrics:** * Reduce number of data points * Use aggregations * Limit table rows * Consider pagination 4. **Lazy load dashboards:** ```javascript theme={"dark"} import { lazy, Suspense } from 'react'; const Dashboard = lazy(() => import('./Dashboard')); }> ``` **Symptoms:** * Page slows down over time * Browser tab crashes * Increasing memory usage **Solutions:** 1. **Clean up on unmount:** ```javascript theme={"dark"} useEffect(() => { const dashboard = document.querySelector('dbn-dashboard'); return () => { // Clean up event listeners if (dashboard) { dashboard.removeEventListener('*', handleEvent); } }; }, []); ``` 2. **Remove event listeners:** ```javascript theme={"dark"} // Don't recreate handler on every render const handleEvent = useCallback((event) => { // Handle event }, []); ``` 3. **Limit re-renders:** ```javascript theme={"dark"} // Use memo for expensive components const MemoizedDashboard = React.memo(Dashboard); ``` ### Cache & Redis Issues **Symptoms:** * Dashboard shows old data after an ETL run or manual data update * Different users see inconsistent data **Solutions:** 1. **Reset cache after data updates:** * Go to **Workspace Settings → Cache Settings** and click **Reset Cache** * This flushes all cached query results for the workspace 2. **Reduce cache TTL:** * If your data updates frequently, lower the cache expiration time * For hourly updates, set TTL to `3600` (1 hour) or less 3. **Verify cache is the cause:** * Temporarily disable caching in **Workspace Settings → Cache Settings** * If the data is now correct, caching was serving stale results **Symptoms:** * Cache settings fail to save with "Invalid Redis credentials" error * Caching enabled but no speed improvement on repeat dashboard loads **Solutions:** 1. **Check network connectivity:** * Your Redis must be reachable from DataBrain's cloud * Verify your security group allows inbound on the Redis port (default `6379`) from DataBrain's IP (see [Allow Access to our IP](/guides/datasources/allow-access-to-our-ip)) * If your Redis is in a private network, contact DataBrain support for connectivity options 2. **Verify credentials:** * Double-check the host, port, and AUTH token * Ensure the AUTH token matches what's configured on your Redis instance * Try connecting to your Redis from another client to rule out credential issues 3. **Check Redis is running:** * Ensure your Redis/Elasticache instance is in an "Available" state * Check for maintenance windows or failover events 4. **Connection timeout:** * DataBrain uses a 5-second connection timeout * If your Redis has high network latency (e.g., cross-region), connections may time out **Symptoms:** * Caching is enabled but dashboards aren't loading faster * Every request seems to hit the database **Solutions:** 1. **Verify caching is enabled:** * Go to **Workspace Settings → Cache Settings** and confirm the toggle is on * Confirm you've set a TTL greater than 0 2. **Check cache mode:** * If using **Databrain Caching**, it should work automatically * If using **BYOC**, verify your Redis connection was validated successfully (save must succeed) 3. **Understand cache key behavior:** * Cache keys include the full query, filters, workspace ID, and datasource ID * Changing any filter or parameter generates a new cache key * Dashboards with many dynamic filters may have lower cache hit rates 4. **Check TTL is reasonable:** * Very short TTLs (e.g., 10 seconds) mean cache entries expire before they can be reused * Start with `3600` (1 hour) and adjust based on your needs ### Framework-Specific Issues **Issue: Component not updating on prop changes** ```javascript theme={"dark"} // ✅ Solution: Use useEffect useEffect(() => { const element = document.querySelector('dbn-dashboard'); if (element && token) { element.setAttribute('token', token); } }, [token]); ``` **Issue: TypeScript errors** ```typescript theme={"dark"} // Add type declaration declare global { namespace JSX { interface IntrinsicElements { 'dbn-dashboard': any; 'dbn-metric': any; } } } ``` **Issue: Next.js SSR errors** ```javascript theme={"dark"} // Use dynamic import with ssr: false import dynamic from 'next/dynamic'; const Dashboard = dynamic( () => import('../components/Dashboard'), { ssr: false } ); ``` **Issue: Vue warnings about unknown custom element** ```javascript theme={"dark"} // vue.config.js or vite.config.js export default { compilerOptions: { isCustomElement: tag => tag.startsWith('dbn-') } } ``` **Issue: Reactive props not updating** ```vue theme={"dark"} ``` **Issue: CUSTOM\_ELEMENTS\_SCHEMA required** ```typescript theme={"dark"} // app.module.ts import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; @NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] }) export class AppModule { } ``` **Issue: Change detection not working** ```typescript theme={"dark"} import { ChangeDetectorRef } from '@angular/core'; constructor(private cdr: ChangeDetectorRef) {} updateToken(newToken: string) { this.token = newToken; this.cdr.detectChanges(); } ``` ## Debugging Tips ### Inspect Component State ```javascript theme={"dark"} // Check component attributes const dashboard = document.querySelector('dbn-dashboard'); console.log({ token: dashboard.getAttribute('token'), dashboardId: dashboard.getAttribute('dashboard-id'), options: dashboard.getAttribute('options') }); ``` ### Monitor Network Requests ```javascript theme={"dark"} // Log all DataBrain API calls const originalFetch = window.fetch; window.fetch = function(...args) { if (args[0].includes('usedatabrain.com')) { console.log('DataBrain API call:', args); } return originalFetch.apply(this, args); }; ``` ## Error Messages Reference For the complete list of error codes with causes and fixes, see the [Error Codes Reference](/developer-docs/reference/error-codes). | Error Message | Cause | Solution | | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `INVALID_TOKEN` | Token not found in this deployment (cloud vs self-hosted mismatch, or embed not receiving the minted value) | Mint against the same environment the embed points at; pass the exact minted token | | `TOKEN_EXPIRED` | Token past its `expiryTime` (tokens without `expiryTime` never expire) | Regenerate token from backend | | `UNAUTHORIZED_ORIGIN` | Page origin not on Whitelist Domains | Add scheme-less `host[:port]` to your Data App's Whitelist Domains | | `UNAUTHORIZED` | ID not in the token's `allowedEmbeds`; or the dashboard doesn't belong to the token's Data App/workspace; or, on dashboard-filter, metric-filter, view, or filter-alias requests, that capability isn't granted | Add the ID at mint time; verify the Data App; for filter/view/alias requests enable the matching Data App access setting or token permission (`params.accessPermissions.isAllowEndUserDashboardFilter`, `isAllowEndUserMetricFilter`, `isAllowDashboardFilterNameChange`, or `isAllowMetricFilterNameChange`; dashboard views use `permissions.isEnableCreateDashboardView`) | | `INVALID_ID` / `Dashboard not found` | Wrong dashboard ID or ID from another Data App | Verify dashboard-id attribute and Data App | | `CORS policy error` | Frontend trying to call API directly | Generate tokens from backend | | `Failed to fetch` | Network or firewall issue | Check network connectivity | | `INVALID_DATA_APP_NAME` | Wrong `dataAppName` in token request (case-sensitive) | Verify Data App name | | `Rate limit exceeded` | Too many API calls | Implement rate limiting/caching | ## Getting Help If you're still stuck after trying these solutions: Use our test environment to isolate issues Check working examples in playground Review complete API specs Contact our support team ## Best Practices to Avoid Issues Never expose API tokens in frontend code. Use your backend to generate guest tokens. Always handle token generation failures and network errors gracefully. Type safety helps catch issues during development. Verify your implementation works in Chrome, Firefox, Safari, and Edge. Set up error tracking (Sentry, LogRocket) to catch issues early. # Token Source: https://docs.usedatabrain.com/developer-docs/token This page is the guide. For the field-by-field API reference of this endpoint, see the canonical [Guest Token API reference](/developer-docs/helpers/api-reference/token) — if the two ever disagree, the API reference wins. To obtain a guest token from DataBrain, utilize our REST API from your backend system. Each request will generate a unique guest token, ensuring security and flexibility. Once you acquire the guest token, you can seamlessly pass it to your frontend application, where it can be integrated with the web component. `Create API key from Databrain's dashboard` that should be passed in the headers in these requests. Guest tokens are designed for frontend embedding. Never expose your API key in frontend code — always generate tokens from your backend. ### Quick start (simple use case): When you need a guest token that you want to use across dashboards and metrics, all you have to do is pass `clientId`, `dataAppName`. If `expiryTime` is not passed, the token will not expire. #### Cloud Databrain Endpoint: ```http theme={"dark"} POST https://api.usedatabrain.com/api/v2/guest-token/create ``` #### Self-hosted Databrain Endpoint: ```http theme={"dark"} POST /api/v2/guest-token/create ``` Generating GUEST TOKEN for your Dashboard/Metric Component. ### Headers | Name | Type | Description | | --------------- | ------ | ---------------------------------------------------------------------------------- | | Authorization\* | String | Bearer [API TOKEN](https://docs.usedatabrain.com/developer-docs/helpers/api-token) | | Content-Type\* | String | Must be set to `application/json` for all requests | ### Request Body | Name | Type | Description | | -------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | dataAppName\* | String | Your Data App Name | | clientId\* | String | Client ID for whom this guest token is generated. (`"clientId": "None"` if no tenancy selected) | | params | Object | Additional Params: `rlsSettings`, `appFilters`, `dashboardAppFilters`, `hideDashboardFilters`, `hideDashboardMetrics`, `allowedEmbeds`, `userIdentifier`, `timezone`, `accessPermissions` | | permissions | Object | Dashboard permission toggles — see [Dashboard Permissions](#dashboard-permissions) below | | expiryTime | Number | Duration in milliseconds from token creation. Common values: `3600000` (1 hour), `86400000` (24 hours), `604800000` (7 days). If omitted, the token never expires | | datasourceName | String | Datasource name from Data Studio (*important in case of multi-datasource embed setup*) | | datamartName | String | Optionally scope the token to a specific Datamart | The request body is validated strictly — any field not listed above is rejected with `INVALID_REQUEST_BODY`. In particular, `dataAppId`, `tenant_id`, `client_id`, and `permissions.dashboards` are **not** valid fields. Use `clientId` and `dataAppName` exactly as spelled here. Guest tokens are free. There is no charge, metering, or purchase involved in generating them — mint as many as you need from your backend. ```json theme={"dark"} // 200: OK { "token": "..." } ``` ```json theme={"dark"} // 400: Bad Request { "error": { "message": "invalid dashboard id", "code": "" } } ``` ```json theme={"dark"} // 401: Unauthorized { "error": { "message": "API key is invalid or expired", "code": "AUTHENTICATION_ERROR" } } ``` ### Request Body Examples: #### Simple Request Body: ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname" } ``` #### Request Body with App Level Metric Filter: > **App filter**\ > A metric level filter designed specifically for controlling access to individual metrics. Unlike general RLS settings, it restricts access without requiring end user input or control. ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "params": { "appFilters": [{ "metricId": "The id of the metric you want to have app filters", "values": { "paid_orders": true, "amount": 500, "country": ["USA", "CANADA"] || "USA", // based on filter variant (select or multi) { "sql": "SELECT \"name\" FROM \"public\".\"countries\" WHERE isEnabled=true", "columnName": "name" } } }] } } ``` ### Dashboard App Filters: #### Request Body with Dashboard filters: ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "params": { "dashboardAppFilters": [ { "dashboardId": "dashboard-id", "values": { // single string "name": "Eric", // multi select "country": ["USA", "CANADA"] || "USA", // based on filter variant (select or multi) { "sql": "SELECT \"name\" FROM \"public\".\"countries\" WHERE isEnabled=true", "columnName": "name" }, // date-picker "timePeriod": { "startDate": "2024-01-01", "endDate": "2024-3-23" }, // range "price": { "min": 1000, "max": 5000 } }, "isShowOnUrl": true // true/false } ] } } ``` In the above code snippet, `"name"`, `"country"`, `"timePeriod"`, and `"price"` are Dashboard App filters.\ When you disable the `isShowOnUrl`, the filter will not be visible to end users as search params on URL. ### Datasource \[Multi Datasource connection]: ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "datasourceName": "data source name" } ``` `datasourceName` is available in app data studio tab. ### Hide Dashboard Filters: To hide dashboard filters in an embedded dashboard: ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "params": { "hideDashboardFilters": ["filter 1", "filter 2"] // name of dashboard filters to hide } } ``` ### Hide Dashboard Metrics: Use `params.hideDashboardMetrics` to hide selected metrics and their layout cards on specific embedded dashboards for this guest token. Each item requires the dashboard's external ID and an array of public metric IDs that are present on that dashboard. ```json theme={"dark"} { "clientId": "id", "dataAppName": "dataappname", "params": { "hideDashboardMetrics": [ { "dashboardId": "sales-overview", "metricIds": ["revenue-by-region", "gross-margin"] } ] } } ``` The dashboard must be within the API token's data app and workspace scope. This setting affects only the matching dashboard's embed response; it does not delete, archive, or change metrics globally. See the [Guest Token API reference](/developer-docs/helpers/api-reference/token) for validation and error details. ### Allowed Embeds (optional) To restrict which dashboards a guest token can load, pass an allowlist of IDs in `params.allowedEmbeds`. When set, the token can only load an embed whose ID (the value you pass to the component's `dashboard-id`/`dashboardId` attribute — an embed ID or dashboard ID both work) is included in the list. Loading any other ID fails with `UNAUTHORIZED`. ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "params": { "allowedEmbeds": ["", ""] } } ``` ### Dashboard Permissions To enable or disable few dashboard permissions from backend: ```json theme={"dark"} { "clientId": "id", //"None" if no tenancy available "dataAppName": "dataappname", "permissions": { "isEnableArchiveMetrics": true, // true or false "isEnableManageMetrics": true, // true or false "isEnableCreateDashboardView": true, // true or false - allow creating custom dashboard views "isEnableMetricUpdation": true, // true or false "isEnableCustomizeLayout": true, // true or false "isEnableUnderlyingData": true, // true or false "isEnableDownloadMetrics": true, // true or false "isShowSideBar": true, // true or false - show the sidebar navigation "isShowDashboardName": true, // true or false - show the dashboard name in the interface "isDisableMetricCreation": false // true or false - disable metric creation for end users } } ``` ### User Identifier for Private & Publish Metrics Use `userIdentifier` inside the `params` object to uniquely identify the end-user in your embedded dashboard.\ This enables features such as creating **private metrics** and **publishing metrics** directly from the embed view. ```json theme={"dark"} { "clientId": "id", "dataAppName": "dataappname", "params": { "userIdentifier": "unique-user-id-123" } } ``` Note: userIdentifier should be a unique string representing the logged-in user in your system. When set, any metrics created by this identifier can be managed (private or published) within the embedded environment. `isAllowPrivateMetricsByDefault` should be enabled while creating the dashboard. ### Timezone Use `timezone` inside the `params` object to specify an IANA timezone string for timezone-aware queries and date/time formatting. When provided, SQL queries will be executed with this timezone setting, ensuring consistent date/time handling across different timezones. **Supported Datasources:** Clickhouse, Trino, Redshift, CockroachDB, Postgres, MSSQL Common timezone values: `"UTC"`, `"America/New_York"`, `"America/Los_Angeles"`, `"Europe/London"`, `"Asia/Kolkata"`, `"Australia/Sydney"` ```json theme={"dark"} { "clientId": "id", "dataAppName": "dataappname", "params": { "timezone": "America/New_York" } } ``` ### End-user Filter Permissions Use `params.accessPermissions` to control end-user dashboard and metric filters, restrict filterable columns, and allow end users to rename filter labels in an embedded experience. Each `*Columns` entry requires a `tableName` and a `columns` array of strings. ```json theme={"dark"} { "clientId": "id", "dataAppName": "dataappname", "params": { "accessPermissions": { "isAllowEndUserDashboardFilter": true, "dashboardFilterColumns": [ { "tableName": "public.sales_data", "columns": ["customer_id", "region"] } ], "isAllowEndUserMetricFilter": true, "metricFilterColumns": [ { "tableName": "public.sales_data", "columns": ["region", "order_date"] } ], "isAllowDashboardFilterNameChange": true, "isAllowMetricFilterNameChange": true } } } ``` When a permission is supplied in the guest token, it takes precedence over the corresponding Data App access setting. See [Update Embedded Filter Alias](/developer-docs/helpers/api-reference/update-filter-alias) to rename a filter through the embedded API. ### Code Examples ```bash cURL (Simple) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "user-456", "dataAppName": "sales-dashboard" }' ``` ```bash cURL (Advanced) icon="fa-solid fa-terminal" theme={"dark"} curl --request POST \ --url https://api.usedatabrain.com/api/v2/guest-token/create \ --header 'Authorization: Bearer dbn_live_abc123...' \ --header 'Content-Type: application/json' \ --data '{ "clientId": "user-456", "dataAppName": "sales-dashboard", "params": { "rlsSettings": [ { "metricId": "metric_123", "values": { "customer_id": "456", "region": "north-america" } } ] }, "expiryTime": 3600000 }' ``` ```javascript Node.js icon="fa-brands fa-node-js" theme={"dark"} const response = await fetch('https://api.usedatabrain.com/api/v2/guest-token/create', { method: 'POST', headers: { 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, body: JSON.stringify({ clientId: 'user-456', dataAppName: 'sales-dashboard', params: { rlsSettings: [ { metricId: 'metric_123', values: { customer_id: '456', region: 'north-america' } } ] }, expiryTime: 3600000 }) }); ``` ```python Python icon="fa-brands fa-python" theme={"dark"} import requests response = requests.post( 'https://api.usedatabrain.com/api/v2/guest-token/create', headers={ 'Authorization': 'Bearer dbn_live_abc123...', 'Content-Type': 'application/json' }, json={ 'clientId': 'user-456', 'dataAppName': 'sales-dashboard', 'params': { 'rlsSettings': [ { 'metricId': 'metric_123', 'values': { 'customer_id': '456', 'region': 'north-america' } } ] }, 'expiryTime': 3600000 } ) ``` ```java Java icon="fa-brands fa-java" theme={"dark"} import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Map; import java.util.List; HttpClient client = HttpClient.newHttpClient(); ObjectMapper mapper = new ObjectMapper(); Map requestBody = Map.of( "clientId", "user-456", "dataAppName", "sales-dashboard", "params", Map.of( "rlsSettings", List.of( Map.of( "metricId", "metric_123", "values", Map.of( "customer_id", "456", "region", "north-america" ) ) ) ), "expiryTime", 3600000 ); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.usedatabrain.com/api/v2/guest-token/create")) .header("Authorization", "Bearer dbn_live_abc123...") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(requestBody))) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); ``` ```php PHP icon="fa-brands fa-php" theme={"dark"} 'user-456', 'dataAppName' => 'sales-dashboard', 'params' => [ 'rlsSettings' => [ [ 'metricId' => 'metric_123', 'values' => [ 'customer_id' => '456', 'region' => 'north-america' ] ] ] ], 'expiryTime' => 3600000 ]; curl_setopt_array($curl, [ CURLOPT_URL => 'https://api.usedatabrain.com/api/v2/guest-token/create', CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => json_encode($data), CURLOPT_HTTPHEADER => [ 'Authorization: Bearer dbn_live_abc123...', 'Content-Type: application/json' ], ]); $response = curl_exec($curl); curl_close($curl); ?> ``` ```ruby Ruby icon="fa-solid fa-gem" theme={"dark"} require 'net/http' require 'json' uri = URI('https://api.usedatabrain.com/api/v2/guest-token/create') http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true request = Net::HTTP::Post.new(uri) request['Authorization'] = 'Bearer dbn_live_abc123...' request['Content-Type'] = 'application/json' request.body = { clientId: 'user-456', dataAppName: 'sales-dashboard', params: { rlsSettings: [ { metricId: 'metric_123', values: { customer_id: '456', region: 'north-america' } } ] }, expiryTime: 3600000 }.to_json response = http.request(request) ``` ```go Go icon="fa-brands fa-golang" theme={"dark"} package main import ( "bytes" "encoding/json" "net/http" ) type RLSValue struct { CustomerID string `json:"customer_id"` Region string `json:"region"` } type RLSSetting struct { MetricID string `json:"metricId"` Values RLSValue `json:"values"` } type Params struct { RLSSettings []RLSSetting `json:"rlsSettings"` } type RequestBody struct { ClientID string `json:"clientId"` DataAppName string `json:"dataAppName"` Params Params `json:"params"` ExpiryTime int `json:"expiryTime"` } func main() { requestBody := RequestBody{ ClientID: "user-456", DataAppName: "sales-dashboard", Params: Params{ RLSSettings: []RLSSetting{ { MetricID: "metric_123", Values: RLSValue{ CustomerID: "456", Region: "north-america", }, }, }, }, ExpiryTime: 3600000, } jsonData, _ := json.Marshal(requestBody) req, _ := http.NewRequest("POST", "https://api.usedatabrain.com/api/v2/guest-token/create", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer dbn_live_abc123...") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() } ``` ```csharp C# icon="fa-solid fa-code" theme={"dark"} using System; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; public class GuestTokenRequest { [JsonProperty("clientId")] public string ClientId { get; set; } [JsonProperty("dataAppName")] public string DataAppName { get; set; } [JsonProperty("params")] public Params Params { get; set; } [JsonProperty("expiryTime")] public int ExpiryTime { get; set; } } public class Params { [JsonProperty("rlsSettings")] public RLSSetting[] RlsSettings { get; set; } } public class RLSSetting { [JsonProperty("metricId")] public string MetricId { get; set; } [JsonProperty("values")] public Values Values { get; set; } } public class Values { [JsonProperty("customer_id")] public string CustomerId { get; set; } [JsonProperty("region")] public string Region { get; set; } } var client = new HttpClient(); var request = new GuestTokenRequest { ClientId = "user-456", DataAppName = "sales-dashboard", Params = new Params { RlsSettings = new[] { new RLSSetting { MetricId = "metric_123", Values = new Values { CustomerId = "456", Region = "north-america" } } } }, ExpiryTime = 3600000 }; var json = JsonConvert.SerializeObject(request); var content = new StringContent(json, Encoding.UTF8, "application/json"); client.DefaultRequestHeaders.Add("Authorization", "Bearer dbn_live_abc123..."); var response = await client.PostAsync("https://api.usedatabrain.com/api/v2/guest-token/create", content); ``` ### HTTP Status Codes | Status Code | Description | | ----------- | ------------------------------------------------- | | `200` | **OK** - Request succeeded | | `400` | **Bad Request** - Invalid request parameters | | `401` | **Unauthorized** - Invalid or missing API key | | `403` | **Forbidden** - Access denied to resource | | `404` | **Not Found** - Resource not found | | `429` | **Too Many Requests** - Rate limit exceeded | | `500` | **Internal Server Error** - Server error occurred | **Rate Limiting**: API requests are limited to prevent abuse. Implement exponential backoff for rate limited requests (429 status). ### Error Codes: | Error Code | HTTP Status | Description | | -------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------- | | `AUTHENTICATION_ERROR` | 401 | Invalid or missing API key | | `INVALID_REQUEST_BODY` | 400 | Missing, invalid, or unknown parameters (unrecognized fields are rejected) | | `CLIENT_ID_ERROR` | 400 | Invalid clientId format or value | | `INVALID_DATA_APP_NAME` | 400 | `dataAppName` doesn't match any Data App (case-sensitive) | | `WORKSPACE_ID_ERROR` | 404 | Workspace not found or inaccessible | | `DASHBOARD_PARAM_ERROR` | 400 | Invalid dashboard filter parameters or a `hideDashboardMetrics` dashboard outside the API token's data app/workspace scope | | `INVALID_METRIC_ID` | 400 | A `hideDashboardMetrics.metricIds` value is not present on the specified dashboard | | `APP_FILTER_PARAM_ERROR` | 400 | Invalid app filter configuration | | `RLS_SETTINGS_PARAM_ERROR` | 400 | Invalid RLS settings | | `DATASOURCE_NAME_ERROR` | 400 | `datasourceName` doesn't resolve | | `DATAMART_NAME_ERROR` | 400 | `datamartName` doesn't resolve | | `INTERNAL_SERVER_ERROR` | 500 | Server error | At embed runtime (after minting), the distinct errors are `INVALID_TOKEN` (token not found in this deployment), `TOKEN_EXPIRED`, `UNAUTHORIZED_ORIGIN`, `UNAUTHORIZED`, and `INVALID_ID` — see the [Error Codes Reference](/developer-docs/reference/error-codes). # Create and Access Your Databrain Account Source: https://docs.usedatabrain.com/getting-started/account-setup Follow this quick guide to sign up for a new Databrain account or sign in to your existing one. # Account Setup ## Sign Up Go to Databrain App and enter your work email. Click **Continue**. Provide your name, company name, and password. Click **Create Account** to complete your registration. Confirm your email address. After verification, you’ll be redirected to your workspace and guided through a detailed setup walkthrough.