Embedded Analytics Developer Guide

Version 0.4.3 | Last Updated: April 2026

QuantumLayers exposes its chart data, statistical analysis, and AI insights through standard WordPress AJAX endpoints secured with Bearer token authentication. This guide explains how to pull live data from a running QuantumLayers installation into any page — without rebuilding the data pipeline.


Table of Contents


Prerequisites

You need access to a running QuantumLayers installation. The third-party page does not need to install or host QL itself — it only needs network access to the QL host.

QL JavaScript Libraries

Both files are served directly from the QL host and can be loaded with a <script> tag:

  • assets/auth.js — exposes the QLAuth object: token storage, the _ajax() wrapper, and sign-in helpers.
  • assets/analytics.js — exposes the QLAnalytics object: chart loading, rendering, and saved-chart management.

Chart.js Setup

QuantumLayers uses Chart.js 4.4.0 and three plugins. Load all four CDN scripts before your own code:


Authentication

Every AJAX request must carry a Bearer token in the Authorization header. Two approaches are available.

Option A — QL Session Token (Same-Origin)

After the user signs in through QL, their token is in localStorage under the key ql_session_token. Read it with QLAuth.getSessionToken():

Option B — Third-Party Provider Registration (Shadow Users)

For cross-origin embeds, the QL operator registers your application in the ql_auth_providers table with three fields:

  • id — unique slug (e.g. "acme-corp"); becomes the kid in the JWT header.
  • name — human-readable label.
  • jwt_secret — shared HMAC-SHA256 secret (HS256).

Your backend mints a signed HS256 JWT with the following structure, then POSTs it to ql_third_party_signin. sub and email are required; first_name and last_name are optional but kept in sync on every login.

Minting the JWT — PHP

With firebase/php-jwt (composer require firebase/php-jwt):

Without an external library (PHP built-ins only):

Minting the JWT — Node.js

With jsonwebtoken (npm install jsonwebtoken):

Without an external library (Node.js built-in crypto):

Once you have the signed token, POST it to QL:

QL verifies the signature, then finds or creates a shadow user identified by provider_id + provider_sub. Email and name are kept in sync on every login. The response contains a standard session_token for all subsequent requests.

Note: ql_try_auth() allows unauthenticated access for public datasets; ql_verify_auth() requires a valid token and is used by all write and analysis endpoints.


Endpoint Reference

All endpoints are reached via POST to https://<QL_HOST>/wp-admin/admin-ajax.php with the action field set as shown.

Dataset Metadata

ql_get_dataset_detail

Queries the ql_datasets table for the dataset record and ql_dataset_columns for its column schema. Access is checked via ql_user_can_read_dataset(), which allows access to datasets owned by the user or shared with their organisation. The column rows include pre-computed statistics (min, max, mean, stddev, distinct count, null count) calculated at upload time — these are the cheapest way to understand a dataset without loading raw rows.

Auth: ql_verify_auth() — valid Bearer token required.

POST params:

  • dataset_id (int, required)

Response:

Chart Data

ql_get_chart_data

Routes to a private method based on chart_type, then returns a complete Chart.js config object (type + data + options) ready to pass to new Chart(ctx, data). All data is loaded from the raw dataset rows up to the plan row limit. Filters are applied in PHP before aggregation. Below is what each chart type actually does internally:

  • histogram — validates the column is numeric, loads raw values, auto-computes 20 equal-width bins using Sturges-style bin width ((max−min)/20), returns a bar chart config with bin ranges as labels and frequency counts as data.
  • time_series / stacked_area — parses every value in time_column via strtotime(), sorts points chronologically, then optionally aggregates into calendar buckets (interval: day/week/month/year) using sum/avg/count/min/max. If cumulative=1, a running total is applied per series after aggregation. Gaps (null Y values) are preserved; Chart.js is instructed not to interpolate across them (spanGaps: false). Returns a line chart config; stacked_area sets fill: true on each dataset.
  • bar / horizontal_bar — validates that category_column is either a string column or a numeric column with fewer distinct values than 10% of row count (i.e. categorical). Groups all rows by category, applies the chosen aggregation (sum/avg/count/min/max) across each value_columns entry, and returns a bar config (indexAxis: 'y' for horizontal).
  • pie / doughnut — groups by category_column, aggregates value_column, sorts descending, and trims to limit categories (default 10). Returns a pie or doughnut config with auto-assigned colours.
  • scatter — loads raw x_column and y_column values as {x, y} point pairs. If color_column is provided, points are split into one dataset per distinct category value. If size_column is provided, the point radius is scaled proportionally to the column value.
  • bubble — identical to scatter but always requires size_column; the radius (r) of each bubble is normalised to a 5–30 px range across the column’s min/max.
  • box_plot / violin — groups raw y_column values by the categories in x_column. Returns data in the format expected by @sgratzl/chartjs-chart-boxplot: arrays of raw values per group, from which the library computes quartiles, whiskers, and outlier dots client-side.
  • heatmap — aggregates z_column for every unique (x_column, y_column) coordinate pair and returns a dataset in the matrix format required by chartjs-chart-matrix: an array of {x, y, v} objects.
  • regression — delegates to analytics.performLinearRegression() (OLS, supports multiple predictors). Returns a bar chart of coefficients with error bars (±1 std error), colour-coded by p-value significance.

Auth: ql_try_auth() — token optional for public datasets, required for private.

Common POST params (all chart types):

  • dataset_id (int, required)
  • chart_type (string, required) — see table below
  • filter_category_column (string, optional) — column to filter rows by exact value
  • filter_category_value (string, optional) — value to match in filter_category_column
  • filter_date_column (string, optional) — date column to range-filter
  • filter_date_from / filter_date_to (string, optional) — ISO date bounds for the date filter

Type-specific params:

chart_typeAdditional POST paramsDefaults
barcategory_column, value_columns[], aggregationaggregation: sum
horizontal_barcategory_column, value_columns[], aggregationaggregation: sum
pie / doughnutcategory_column, value_column, aggregation, limitaggregation: sum, limit: 10
scatterx_column, y_column, color_column (opt), size_column (opt)
bubblex_column, y_column, size_column, color_column (opt)
box_plot / violinx_column (categories), y_column (values)
heatmapx_column, y_column, z_column, aggregationaggregation: average
time_seriestime_column, value_columns[], aggregation, interval, cumulativeaggregation: sum, interval: day, cumulative: 0
stacked_areatime_column, value_columns[], aggregation, intervalaggregation: none, interval: day
histogramcolumn_name
regressiony_column, x_columns[]

Response: A Chart.js config object you can pass directly to new Chart(ctx, data). On error: { success: false, data: { error: "..." } }.

ql_get_recommended_charts

Runs the full rule-based insight pipeline (same as ql_get_insights but without the AI call) and converts each insight into a chart candidate. Candidates are scored by insight_score (0–100), the top max_charts are kept, and actual Chart.js data is generated for each one via generateChartData(). Any candidate whose chart generation returns an error is silently dropped. The result is an opinionated, ranked list of charts that best reveal patterns in the data — useful for auto-populating a dashboard without any user configuration.

Auth: ql_verify_auth() — valid Bearer token required.

POST params:

  • dataset_id (int, required)
  • max_charts (int, optional, default: 20)
  • selected_columns[] (array of strings, optional) — restrict analysis to these columns
  • Filter params: same filter_category_column/value and filter_date_* as ql_get_chart_data

Response:

ql_save_chart

Recursively sanitises the chart_params array and serialises it to JSON, then inserts a row into ql_saved_charts (columns: dataset_id, user_id, chart_name, chart_type, chart_params, created_at). The chart_params value is the exact set of type-specific params you would pass to ql_get_chart_data — store the params from a chart you already rendered and you can reconstruct it later without re-running analysis.

Auth: ql_verify_auth() — valid Bearer token required.

POST params:

  • dataset_id (int, required)
  • chart_type (string, required)
  • chart_params (array, required) — the same type-specific params used in ql_get_chart_data, stored as JSON
  • chart_name (string, optional) — human-readable label

Response: { "message": "Chart saved successfully", "chart_id": 17 }

ql_get_saved_charts

Selects all rows from ql_saved_charts where dataset_id and user_id match, ordered newest-first. The chart_params field is a JSON string — parse it with JSON.parse() and pass the result directly to ql_get_chart_data to re-render the chart on demand.

Auth: ql_verify_auth() — valid Bearer token required.

POST params: dataset_id (int, required)

Response:

Note: chart_params is a JSON string. Parse it and pass to ql_get_chart_data to re-render the chart.

ql_delete_saved_chart

Fetches the ql_saved_charts row by chart_id and user_id before deleting — a chart belonging to a different user returns a 404-style error even if the chart_id exists. This ownership check is the only authorisation gate; no dataset access check is performed.

Auth: ql_verify_auth() — valid Bearer token required.

POST params: chart_id (int, required)

Response: { "message": "Chart deleted successfully" }

Statistical Analysis

ql_get_statistical_summary

Iterates every numeric column (inferred_type of integer or float) whose distinct_count exceeds 10% of the dataset’s row count — this threshold filters out effectively categorical numerics like status codes or boolean flags. For each qualifying column, min/max/mean/std are read directly from the pre-computed ql_dataset_columns row (no raw-data load needed). The raw column values are then loaded once to compute median, Q1, Q3, skewness (third standardised moment), and kurtosis (fourth standardised moment minus 3 — i.e. excess kurtosis).

Auth: ql_verify_auth() — valid Bearer token required.

POST params: dataset_id (int, required)

Response: array of per-column objects:

ql_get_correlation_matrix

Selects all continuous numeric columns (same 10%-distinct threshold as the statistical summary), loads their raw values, then computes the full Pearson r matrix in PHP. The result is cached as a WordPress transient for one hour — the cache key includes the dataset ID, so a second call within the hour returns instantly without reloading data. Requires at least two qualifying columns; returns an error otherwise. The cache is per-dataset (not per-user), so all users sharing a dataset see the same cached matrix.

Auth: ql_verify_auth() — valid Bearer token required.

POST params: dataset_id (int, required)

Response:

matrix[i][j] is the Pearson r between columns[i] and columns[j]. Values range from −1 to 1.

ql_get_distribution_analysis

Loads all non-null numeric values for the requested column, sorts them, and computes: mean, variance, std, range, IQR, full percentile set (p5/Q1/median/Q3/p95), skewness (third standardised moment), and excess kurtosis. Outliers are detected using the 1.5×IQR fence rule: values below Q1 − 1.5×IQR or above Q3 + 1.5×IQR are flagged. Up to 50 outlier values are returned in the response. Normality is classified as approximately normal (|skewness| < 0.5 and |kurtosis| < 0.5), non-normal (either exceeds 1), or moderately skewed otherwise. The column must be integer or float; string and date columns return an error.

Auth: ql_verify_auth() — valid Bearer token required.

POST params: dataset_id (int, required), column_name (string, required)

Response:

ql_get_pca_analysis

Selects continuous numeric columns (10%-distinct threshold), loads raw values, z-score standardises each column (subtract mean, divide by std), then builds the covariance matrix. Eigenvalues and eigenvectors are computed using the Power Iteration method implemented in PHP. Components are sorted by eigenvalue descending. The transformed data (PC scores) is capped at the first 1,000 rows in the response to limit payload size. Results are cached for one hour keyed by dataset_id + n_components. If n_components is less than 2 or omitted, all components are returned. Requires at least 2 qualifying columns and 10 rows.

Auth: ql_verify_auth() — valid Bearer token required.

POST params:

  • dataset_id (int, required)
  • n_components (int, optional) — number of components to return; if omitted or less than 2, defaults to the total number of eligible columns

Response:

ql_get_anova_analysis

For every pair of (categorical column × continuous numeric column), runs a one-way ANOVA: groups numeric values by category label, computes Sum of Squares Between (SSB) and Within (SSW), derives the F-statistic (MSB/MSW), and approximates the p-value using an incomplete beta function (no external statistics library). Additionally computes Cohen’s d between the two groups with the largest pairwise mean difference, as a standardised effect-size measure. eta_squared = SSB / (SSB + SSW) gives the proportion of variance explained by the grouping. The significance label is derived from the p-value: not_significant (p ≥ 0.05), moderately_significant (p < 0.05), highly_significant (p < 0.01), or insufficient_data (fewer than 3 rows or fewer than 2 groups).

Auth: ql_verify_auth() — valid Bearer token required.

POST params: dataset_id (int, required)

Response:

AI Insights

ql_get_insights

Two-stage pipeline. Stage 1 — rule-based insights (always runs): nine parallel analyses each produce typed insight objects, which are merged into one list:

  • Correlation — flags strong Pearson r relationships (|r| > threshold) between numeric columns.
  • ANOVA — flags categorical columns that significantly explain variance in a numeric column (F-test p < 0.05).
  • Distribution — flags high skewness, excess kurtosis, and columns with a high outlier rate.
  • Temporal — detects monotonic trends and seasonality in date/time columns.
  • Regression — runs OLS on numeric column pairs and surfaces strong predictive relationships.
  • Categorical — measures distribution entropy per categorical column; flags highly imbalanced or highly uniform distributions.
  • Categorical relationships — runs chi-square tests between pairs of categorical columns to detect non-independence.
  • Cross-correlation — detects lagged relationships between time series; first runs an ADF stationarity test and differences non-stationary series before computing cross-correlation.
  • Multicollinearity (VIF) — computes Variance Inflation Factor for each numeric column; flags predictors with VIF above threshold as redundant.

All insights that carry a p-value in their metadata are then subjected to Benjamini-Hochberg FDR correction at α = 0.05, removing insights that become non-significant after accounting for multiple comparisons. The surviving insights are sorted by importance descending and truncated to max_insights.

Stage 2 — AI holistic analysis (runs only if an Anthropic or OpenAI key is configured and the user’s monthly token budget is not exhausted): compiles a dataset context object (column stats, top rule-based insights, top 5 chart candidates) and sends it to ql_call_llm() with a 4,000-token budget and the system prompt “You are an expert data analyst who provides clear, actionable insights for business users.” If a user_prompt is supplied, it is appended to steer the analysis. The AI response is prepended to the insight array as a holistic_analysis type object with importance: 100. If the token budget is exceeded, a warning insight is prepended instead and the AI call is skipped.

Auth: ql_verify_auth() — valid Bearer token required.

POST params:

  • dataset_id (int, required)
  • selected_columns[] (array, optional) — restrict insights to these columns
  • max_insights (int, optional) — capped at the plan limit; defaults to plan maximum
  • user_prompt (string, optional) — freeform question or instruction passed to the AI for the holistic analysis
  • Filter params: filter_category_column, filter_category_value, filter_date_column, filter_date_from, filter_date_to

Response:

Note: The first element is the AI holistic insight (if AI is configured and the token budget is not exhausted). Remaining elements are rule-based insights sorted by importance descending.


Dataset Management

These endpoints create, update, sync, and delete datasets. Every source type (CSV upload, SQL, REST API, SFTP, Google Sheets, and merged) has its own set of handlers. All write operations use ql_verify_auth() and check dataset ownership via ql_user_can_write_dataset() before acting. The visibility parameter is accepted by all create/update handlers and must be one of private, public, org, or group.

CSV Upload

ql_upload_dataset

Creates a new dataset from a CSV file upload. The file is validated against an allowlist of MIME types (text/csv, text/plain, application/csv, application/vnd.ms-excel) using finfo — not just the file extension. File size is checked against the plan limit before the file is moved. The file is saved to wp-uploads/quantumlayers/<dataset_id>_<timestamp>.csv and its SHA-256 checksum stored in ql_dataset_files. The dataset row is created with status = 'processing' and then ql_process_csv_file() is called synchronously: it reads the CSV header to detect column names, samples rows to infer types (integer/float/string/date/datetime), and computes per-column statistics (min, max, mean, stddev, distinct count, null count) stored in ql_dataset_columns. The status is set to ready on success.

Auth: ql_verify_auth(). Request type: multipart/form-data.

  • csv_file (file, required) — the CSV file
  • dataset_name (string, required)
  • visibility (string, optional, default: private)

Response: { "message": "Upload successful!", "dataset_id": 42, "dataset_name": "sales_2024" }

ql_update_upload_dataset

Updates metadata and/or replaces the CSV data for an existing source_type = 'upload' dataset. Rejects datasets of other source types with an explicit error. If a new csv_file is included it is processed via the shared ql_process_uploaded_csv() helper, which replaces the stored file, re-runs column analysis, and updates ql_dataset_columns and row_count. Metadata changes (dataset_name, visibility) and CSV replacement can be combined in a single call — the response message describes which operations occurred.

Auth: ql_verify_auth() + ownership check. Request type: multipart/form-data.

  • dataset_id (int, required)
  • dataset_name (string, optional)
  • visibility (string, optional)
  • csv_file (file, optional) — if provided, replaces the dataset’s data

Response: { "message": "...", "row_count": 15000 } (row_count present only when a CSV was processed).

ql_resync_upload_dataset

Replaces a CSV upload dataset’s data with a newly uploaded file, without changing any metadata. Equivalent to ql_update_upload_dataset with only a csv_file and no metadata fields. A convenience endpoint for sync-only workflows.

Auth: ql_verify_auth() + ownership check. Request type: multipart/form-data.

  • dataset_id (int, required)
  • csv_file (file, required)

Response: { "success": true, "message": "...", "row_count": 15000 }


SQL Database

ql_connect_sql_database

Creates a live SQL-backed dataset. Supported db_type values are mysql and postgresql. The connection is tested via ql_test_database_connection() before any database rows are written — a failed test returns an error immediately. On success: a ql_datasets row is created with source_type = 'db', the password is encrypted with ql_encrypt_credential() and stored in ql_sql_connections, then ql_sync_sql_connection() executes sql_query against the remote database, streams the result set into QL’s internal storage, and runs full column analysis. The default port is 3306 for MySQL and 5432 for PostgreSQL if omitted.

Auth: ql_verify_auth().

  • dataset_name (string, required)
  • db_type (string, required) — mysql or postgresql
  • host (string, required)
  • port (int, optional) — defaults to 3306 / 5432
  • database (string, required) — database/schema name
  • username (string, required)
  • password (string, required)
  • sql_query (string, required) — the SELECT query whose result set becomes the dataset
  • visibility (string, optional)

Response: { "message": "Database connected successfully", "dataset_id": 42, "connection_id": 7, "rows_fetched": 5000 }. If the initial sync fails but the connection was stored, a "warning": true flag is added and rows_fetched is omitted.

ql_update_sql_connection

Updates credentials, query, or metadata for an existing SQL connection. Identified by connection_id. Any field can be omitted to leave it unchanged; if a new password is supplied it is re-encrypted. Does not re-sync data — call ql_resync_connection after updating to pull fresh data.

Auth: ql_verify_auth() + ownership check on connection_id.

  • connection_id (int, required)
  • dataset_name, db_type, host, port, database_name, username, password, sql_query, visibility (all optional)

Response: { "message": "Connection updated successfully" }


REST API

ql_connect_api

Creates a dataset backed by a REST API endpoint. The URL is validated with a scheme check (http:// or https://) rather than FILTER_VALIDATE_URL to support URLs with colons in path segments (e.g. GA4’s /properties/123:runReport). A live connection test is performed before any rows are written. The API key is encrypted with ql_encrypt_credential(). Supports OAuth2: if a refresh_token is provided, QL stores it and automatically refreshes the access token when it is within 5 minutes of expiry at sync time. Custom request_headers are stored as a JSON string and merged with the default Authorization and Accept: application/json headers on every sync. response_path is a dot-notation path into the JSON response used to locate the array of records (e.g. data.items).

Auth: ql_verify_auth().

  • dataset_name (string, required)
  • api_url (string, required)
  • http_method (string, optional) — GET (default) or POST
  • api_key (string, optional) — sent as Authorization: Bearer <key>
  • request_headers (JSON string or array, optional) — extra headers merged at sync time
  • request_body (string, optional) — raw body for POST requests; sets Content-Type: application/json
  • response_path (string, optional) — dot-notation path to the records array in the JSON response
  • refresh_token (string, optional) — OAuth2 refresh token
  • oauth_provider_name (string, optional)
  • oauth_scope (string, optional)
  • visibility (string, optional)

Response: { "message": "API connected successfully", "dataset_id": 42, "connection_id": 9, "rows_fetched": 1200 }

ql_update_api_connection

Updates credentials, headers, URL, or metadata for an existing API connection identified by connection_id. Any field can be omitted to leave it unchanged. Does not re-sync — call ql_resync_connection afterwards.

Auth: ql_verify_auth() + ownership check. POST params: connection_id (required) + any subset of the fields accepted by ql_connect_api.


SFTP

ql_create_sftp_connection

Creates a dataset backed by a file on an SFTP server. Supports password auth or private key auth — at least one must be supplied. Both credentials are encrypted with ql_encrypt_credential() before storage. A live connection test (ql_sftp_test_connection()) is performed first; if it fails no rows are written. On success, ql_sftp_sync_dataset() downloads the file at remote_path/filename, processes it as a CSV, and runs full column analysis. The dataset is created with source_type = 'sftp'.

Auth: ql_verify_auth().

  • dataset_name (string, required)
  • host (string, required)
  • port (int, optional, default: 22)
  • username (string, required)
  • password (string, optional) — required if private_key not provided
  • private_key (string, optional) — PEM private key; required if password not provided
  • remote_path (string, required) — directory path on the SFTP server
  • filename (string, required) — filename within remote_path
  • visibility (string, optional)

Response: { "dataset_id": 42, "connection_id": 3, "rows_fetched": 8000 }

ql_update_sftp_connection

Updates host, credentials, remote path, filename, or metadata for an existing SFTP connection. Any field can be omitted. Does not re-sync — call ql_sync_sftp_dataset after updating.

Auth: ql_verify_auth() + ownership check. POST params: connection_id (required) + any subset of ql_create_sftp_connection fields.

ql_sync_sftp_dataset

Triggers an immediate re-download and re-import of the file from the SFTP server for an existing SFTP connection. Decrypts stored credentials, opens the SSH connection, downloads the file, replaces the stored CSV data, and re-runs column analysis.

Auth: ql_verify_auth() + ownership check. POST params: connection_id (int, required).

Response: { "message": "Dataset synced successfully", "row_count": 8500 }


Google Sheets

ql_connect_google_sheet

Creates a dataset backed by a Google Sheet. Requires an OAuth2 access_token obtained via the Google Picker flow (scope: drive.file). Because drive.file tokens are rejected by the Sheets API, QL uses the Drive API export endpoint (/export?mimeType=text/csv) to download the sheet as CSV. A connection test is performed before writing any rows. The access token is stored in plaintext in ql_google_sheet_connections and a 1-hour expiry is calculated; at sync time, if the token is within 1 hour of expiry, ql_refresh_google_token() is called automatically using the stored refresh_token. If range_notation is omitted, the entire sheet is imported.

Auth: ql_verify_auth().

  • spreadsheet_id (string, required) — Google Sheets spreadsheet ID
  • access_token (string, required) — current OAuth2 access token
  • connection_name (string, optional, default: "Google Sheet Connection") — becomes the dataset name
  • sheet_name (string, optional, default: "Sheet1")
  • range_notation (string, optional) — A1 notation range, e.g. A1:F500
  • refresh_token (string, optional)
  • visibility (string, optional)

Response: { "message": "Google Sheets connected successfully", "dataset_id": 42, "connection_id": 5 }

ql_update_google_sheet_connection

Updates the spreadsheet ID, sheet name, range, tokens, or dataset metadata for an existing Google Sheet connection. Any field can be omitted. Does not re-sync — call ql_resync_connection after updating.

Auth: ql_verify_auth() + ownership check. POST params: connection_id (required) + any subset of ql_connect_google_sheet fields.


Merged Datasets

ql_create_merged_dataset

Joins two or more existing datasets on shared columns and materialises the result as a new dataset with source_type = 'merged'. Requires at least 2 datasets. The first dataset in the array is the base; each subsequent entry specifies a join column (which must exist in that dataset) and a join type. Joins are chained left-to-right: dataset 2 joins onto dataset 1, dataset 3 joins onto the result of that join, and so on. Join records are stored in ql_dataset_joins. After the join records are created, ql_build_merged_columns() reads the column schemas of all source datasets and writes the merged column schema. The actual row data is assembled at query time from the source datasets — no copy of the rows is stored. Always created as visibility = 'private'.

Auth: ql_verify_auth().

Response: { "success": true, "dataset_id": 55 }

ql_update_merged_dataset

Replaces the name and entire join configuration of an existing merged dataset. All existing ql_dataset_joins rows for the dataset are deleted and re-created from the new datasets array using the same chaining logic as ql_create_merged_dataset. The underlying source data is not touched.

Auth: ql_verify_auth() + ownership check.

  • dataset_id (int, required) — must be a source_type = 'merged' dataset
  • name (string, required)
  • datasets (array, required) — same structure as ql_create_merged_dataset

Response: { "message": "Merged dataset updated successfully" }


Common Operations

ql_resync_connection

Re-fetches data from the remote source for any connected dataset (source_type of db, api, or google_sheet). Looks up the connection record for the dataset’s source type, then delegates to the appropriate sync function: ql_sync_sql_connection(), ql_sync_api_connection(), or ql_sync_google_sheet_connection(). For Google Sheets, optional fresh access_token / refresh_token values can be passed in the same request to update tokens before syncing.

Auth: ql_verify_auth() + ownership check.

  • dataset_id (int, required)
  • access_token (string, optional) — Google Sheets only
  • refresh_token (string, optional) — Google Sheets only

Response: { "message": "Data synced successfully", "row_count": 5200 }

ql_delete_dataset

Permanently deletes a dataset and all associated data. Access is checked via ql_user_can_write_dataset(). Deletion cascades through every related table in order: physical CSV files are deleted from wp-uploads/quantumlayers/ first, then rows are removed from ql_dataset_files, ql_dataset_columns, ql_dataset_joins, ql_google_sheet_connections, ql_api_connections, ql_sql_connections, ql_sftp_connections, and finally ql_datasets. Saved charts and insights for the dataset are also removed. This operation is irreversible.

Auth: ql_verify_auth() + ql_user_can_write_dataset().

  • dataset_id (int, required)

Response: { "message": "Dataset deleted successfully" }

ql_set_dataset_visibility

Changes the visibility of any dataset. Also registered as ql_toggle_dataset_privacy for backward compatibility. Accepts the modern visibility string parameter or the legacy is_public boolean (0 = private, 1 = public); if both are sent, visibility takes precedence. Access is checked via ql_user_can_write_dataset().

Auth: ql_verify_auth() + ql_user_can_write_dataset().

  • dataset_id (int, required)
  • visibility (string) — private | public | org | group
  • is_public (int, legacy) — 0 = private, 1 = public; ignored if visibility is present

Response: { "message": "Visibility updated to public" }


Complete Code Example

End-to-end: authenticate via a third-party JWT, fetch a bar chart for dataset 42, and render it with Chart.js.


Chart Type Quick Reference

Pass one of the following values as chart_type to ql_get_chart_data.

chart_typeRequired paramsChart.js type rendered
barx_column, y_column, aggregationbar
horizontal_barx_column, y_column, aggregationbar (indexAxis: ‘y’)
linex_column, y_column, aggregationline
scatterx_column, y_columnscatter
piecategory_column, value_column, aggregationpie
doughnutcategory_column, value_column, aggregationdoughnut
bubblex_column, y_column, size_columnbubble
box_plotcategory_column, value_columnboxplot (chartjs-chart-boxplot)
heatmapx_column, y_column, value_columnmatrix (chartjs-chart-matrix)
time_seriesdate_column, value_column, aggregationline (time scale)
histogramcolumn_name, optional binsbar (computed bins)
areax_column, y_column, aggregationline (fill: true)