Create or update insight
Create a new insight, or update an existing one when an id is included in the body. Requires an agency key (ak_) and ?location_id=. On update, the insight must belong to the resolved location. Returns the saved row.
The body is validated on write: config.query must be a valid explore spec and its kind must match insight_type (funnel ⇔ funnel; every other type draws a trend). A bad config is a 400 here, never a 500 on the first run.
curl -X POST "https://mythic-analytics.gulp.workers.dev/builder/insights?location_id=acme-retail" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_TOKEN" \
-d '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "Unique visitors per day, last 30 days vs the 30 before",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
}
}'
import requests
import json
url = "https://mythic-analytics.gulp.workers.dev/builder/insights?location_id=acme-retail"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
}
data = {
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "Unique visitors per day, last 30 days vs the 30 before",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
}
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
const response = await fetch("https://mythic-analytics.gulp.workers.dev/builder/insights?location_id=acme-retail", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_API_TOKEN"
},
body: JSON.stringify({
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "Unique visitors per day, last 30 days vs the 30 before",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
}
})
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"net/http"
"bytes"
"encoding/json"
)
func main() {
data := []byte(`{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "Unique visitors per day, last 30 days vs the 30 before",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
}
}`)
req, err := http.NewRequest("POST", "https://mythic-analytics.gulp.workers.dev/builder/insights?location_id=acme-retail", bytes.NewBuffer(data))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer YOUR_API_TOKEN")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
fmt.Println("Response Status:", resp.Status)
}
require 'net/http'
require 'json'
uri = URI('https://mythic-analytics.gulp.workers.dev/builder/insights?location_id=acme-retail')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request['Authorization'] = 'Bearer YOUR_API_TOKEN'
request.body = '{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "Unique visitors per day, last 30 days vs the 30 before",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
}
}'
response = http.request(request)
puts response.body
{
"data": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"location_id": "acme-retail",
"data_connection_id": "123e4567-e89b-12d3-a456-426614174000",
"created_by": "123e4567-e89b-12d3-a456-426614174000",
"name": "Daily visitors",
"description": "example_string",
"insight_type": "number",
"config": {
"query": {
"kind": "trend",
"date_range": {
"preset": "30d"
},
"interval": "day",
"series": [
{
"event": "$pageview",
"math": "dau",
"label": "Visitors"
}
],
"compare": "previous_period"
}
},
"visualization": {},
"is_embeddable": false,
"embed_token": "9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c",
"tags": [
"funnel",
"paid"
],
"canvas_id": "123e4567-e89b-12d3-a456-426614174000",
"is_favorite": false,
"created_at": "2024-12-25T10:00:00Z",
"updated_at": "2024-12-25T10:00:00Z"
}
}
{
"error": "Bad Request",
"message": "The request contains invalid parameters or malformed data",
"code": 400,
"details": [
{
"field": "email",
"message": "Invalid email format"
}
]
}
{
"error": "Forbidden",
"message": "You don't have permission to access this resource",
"code": 403
}
/insights
Target server for requests. Edit to use your own host.
Builder key as a bearer token. Use an agency key (Bearer ak_...) for writes, or a viewer key (Bearer sk_...) for reads. Scoped keys (mcp_) with insights:read/insights:write are accepted too.
Bearer ak_...) for writes, or a viewer key (Bearer sk_...) for reads. Scoped keys (mcp_) with insights:read/insights:write are accepted too.Client location to scope the request to. Required when authenticating with an agency key (ak_). Ignored for viewer keys (sk_).
The media type of the request body
Include to update an existing insight; omit to create.
Visualization only. funnel draws a kind: funnel spec; the others draw a kind: trend spec (line/table want an interval, number/bar/pie usually don't).
query is an explore spec — the same object POST /client/v1/data/query takes; the full grammar is on the Explore queries page and a per-type walkthrough on the Insight config reference. Any other key is stored verbatim as display settings and never read by the runner.
Request Preview
Response
Response will appear here after sending the request
Authentication
Bearer token. Builder key as a bearer token. Use an agency key (Bearer ak_...) for writes, or a viewer key (Bearer sk_...) for reads. Scoped keys (mcp_) with insights:read/insights:write are accepted too.
Query Parameters
Client location to scope the request to. Required when authenticating with an agency key (ak_). Ignored for viewer keys (sk_).
acme-retailBody
Include to update an existing insight; omit to create.
Daily visitorsUnique visitors per day, last 30 days vs the 30 beforeVisualization only. funnel draws a kind: funnel spec; the others draw a kind: trend spec (line/table want an interval, number/bar/pie usually don't).
numberlinebarpietablefunnelquery is an explore spec — the same object POST /client/v1/data/query takes; the full grammar is on the Explore queries page and a per-type walkthrough on the Insight config reference. Any other key is stored verbatim as display settings and never read by the runner.
{"query":{"kind":"trend","date_range":{"preset":"30d"},"interval":"day","series":[{"event":"$pageview","math":"dau","label":"Visitors"}],"compare":"previous_period"}}