Skip to main content

Snapshot API

The Snapshot API renders on-chain analytics charts as PNG images or SVG vector graphics. Send metric IDs and optional display parameters, and receive a fully-rendered chart image ready for embedding in reports, dashboards, or AI conversations. Currently supports Bitcoin metrics, with multi-chain coverage (ETH, TON, TRON) expanding.

Endpoints

MethodPathDescription
GET/v1/chart/snapshotSimple charts via query parameters
POST/v1/chart/snapshotFull customization via JSON body

Both endpoints return image/png by default.

Authentication

All requests require an API key via the Authorization header:

Authorization: Bearer YOUR_API_KEY

See Authentication for details on obtaining API keys.

Access & Rate Limits

The Snapshot API requires Pro or Enterprise tier. Demo and Free tier keys receive 403 Forbidden.

Snapshot API follows the same rate limits as the Data API. See Rate Limits for details.

When rate limited, the API returns 429 Too Many Requests with a retry_after field.

Metric access is also grade-gated: grade 0 metrics (price, supply, MVRV) are available to all Pro+ keys, grade 1 metrics (SOPR, P&L) require Pro, and grade 2 metrics (CBD heatmaps) require Enterprise.


GET /v1/chart/snapshot

Generate a chart from query parameters. Best for simple, single-metric or template-based charts.

Parameters

ParameterTypeDefaultDescription
metricstring-Single metric ID (e.g., price, lth_supply). Mutually exclusive with metrics and template.
metricsstring-Comma-separated metric IDs, max 6 (e.g., lth_supply,sth_supply). Mutually exclusive with metric and template.
templatestring-Predefined template ID. Mutually exclusive with metric and metrics.
daysinteger365Days of historical data (7-10000).
start_datestring-Start date (YYYY-MM-DD). Overrides days.
end_datestring-End date (YYYY-MM-DD). Defaults to today.
stylestringautoChart style: line, area, bar. Auto-detected from metric registry if omitted.
scalestringlinearY-axis scale: linear or log.
overlaystring-Add price overlay as a subtle dashed line on the right axis (use price). Currently BTC price.
widthinteger1200Image width in pixels (600-2400).
heightinteger600Image height in pixels (300-1200).
titlestringautoChart title. Auto-generated from metric names if omitted.
themestringlightColor theme: light or dark.

Exactly one of metric, metrics, or template must be provided.

Available Templates

TemplateMetrics
priceBTC Price
price_volumePrice + Volume
market_capMarket Cap
holder_supplyLTH Supply + STH Supply
mvrv_ratioLTH MVRV + STH MVRV
realized_priceLTH Realized Price + STH Realized Price
realized_capLTH Realized Cap + STH Realized Cap
unrealized_plLTH Unrealized P/L + STH Unrealized P/L
realized_plLTH Realized P/L + STH Realized P/L
soprLTH SOPR + STH SOPR
block_heightBlock Height

Examples

# Bitcoin example: BTC price, 1 year, line chart
curl -H "Authorization: Bearer YOUR_KEY" \
"https://api.blocklens.co/v1/chart/snapshot?metric=price" \
--output price.png

# Bitcoin example: two metrics with area style
curl -H "Authorization: Bearer YOUR_KEY" \
"https://api.blocklens.co/v1/chart/snapshot?metrics=lth_supply,sth_supply&style=area&days=730" \
--output supply.png

# Template with dark theme
curl -H "Authorization: Bearer YOUR_KEY" \
"https://api.blocklens.co/v1/chart/snapshot?template=mvrv_ratio&theme=dark" \
--output mvrv_dark.png

# Log scale with price overlay
curl -H "Authorization: Bearer YOUR_KEY" \
"https://api.blocklens.co/v1/chart/snapshot?metric=lth_supply&scale=log&overlay=price&days=1095" \
--output supply_with_price.png

# Get JSON metadata instead of image
curl -H "Authorization: Bearer YOUR_KEY" \
-H "Accept: application/json" \
"https://api.blocklens.co/v1/chart/snapshot?metric=price" | jq

# Get SVG instead of PNG
curl -H "Authorization: Bearer YOUR_KEY" \
-H "Accept: image/svg+xml" \
"https://api.blocklens.co/v1/chart/snapshot?metric=price" \
--output price.svg

Success Response

HTTP/1.1 200 OK
Content-Type: image/png
Cache-Control: public, max-age=3600
X-Snapshot-Cache: HIT
X-Snapshot-Render-Ms: 0

<binary PNG data>

POST /v1/chart/snapshot

Full chart customization via JSON body. Supports per-metric styling, custom axes, formulas, reference lines, reference areas, and more. Designed for AI agents (via MCP) and advanced users.

Request Body

Provide exactly one data source (metric, metrics, or template):

{
"metric": "price",

"days": 365,
"start_date": "2025-01-01",
"end_date": "2026-02-23",

"title": "Custom Chart Title",
"width": 1200,
"height": 600,
"theme": "light",
"format": "png",

"style": "line",
"scale": "linear",
"overlay": "price",

"y_axes": [
{"id": "axis-left", "side": "left", "scale": "linear", "format": "number"},
{"id": "axis-right", "side": "right", "scale": "log", "format": "currency"}
],

"formulas": [
{"expression": "sma(m1, 200)", "label": "200-day SMA", "color": "#9333ea", "style": "line"}
],

"reference_lines": [
{"y": 1.0, "stroke": "#9ca3af", "stroke_dasharray": "3 3", "label": "Break-even"}
],
"reference_areas": [
{"y1": 0, "y2": 0.85, "fill": "#16a34a", "fill_opacity": 0.08, "label": "Undervalued"}
]
}

Note: Exactly one of metric, metrics, or template must be provided.

Metrics Field

The metrics field supports mixed types:

// String shorthand
["price", "lth_supply"]

// Full config objects
[{"id": "price", "axis": "right", "style": "line", "color": "#374151"}]

// Mixed
["price", {"id": "lth_supply", "axis": "left", "style": "area"}]

// With params for parameterized metrics
[
{"id": "funding_binance", "params": {"exchange": "binance"}},
{"id": "price"}
]

Some metrics require additional parameters (e.g., exchange, ticker, id). Include the params object from the metric definition when using these metrics.

Per-Metric Options

FieldTypeDescription
idstringRequired. Metric ID from registry.
paramsobjectParameters for parameterized metrics (e.g., {"exchange": "binance"}). See metric definition for required params.
axisleft / rightY-axis side. Auto-assigned if omitted.
y_axis_idstringBind to a specific Y-axis by ID (e.g. axis-diff). Overrides axis.
styleline / area / barChart style. Registry default if omitted.
colorstringHex color (e.g., #2563eb). Auto-assigned if omitted.
labelstringDisplay label. Uses metric name if omitted.
stroke_widthintegerLine width (0-5). Default: 2. Use 0 for bars without borders.
fill_opacityfloatFill opacity (0.0-1.0). For transparent bars, use low values like 0.2.
stroke_dashstringDash pattern (e.g., 5 5).
stack_groupstringStack group ID for stacked charts.
show_in_legendbooleanWhether to show in the chart legend. Default: true.
visiblebooleanShow/hide. Default: true.

Custom Y-Axes

The y_axes field defines the Y-axes available to metrics and formulas. Each axis has a unique id that can be referenced via y_axis_id on metrics or formulas. You can define more than two axes — for example, a separate axis for computed differences:

"y_axes": [
{"id": "axis-left", "side": "left", "scale": "linear", "format": "number"},
{"id": "axis-right", "side": "right", "scale": "log", "format": "currency"},
{"id": "axis-diff", "side": "left", "scale": "linear", "format": "number"}
]
FieldTypeDescription
idstringUnique axis identifier. Referenced by y_axis_id on metrics/formulas.
sideleft / rightWhich side of the chart the axis appears on.
scalelinear / logAxis scale. Default: linear.
formatnumber / currency / percentNumber format for axis labels.
range[number, number]Vertical zone as [from%, to%]. 0 = bottom, 100 = top. Default: full height. Use to stack axes vertically (e.g. volume in bottom 20%, price in top 80%).
domain_minnumberHard minimum domain clamp. The axis will never go below this value.
domain_maxnumberHard maximum domain clamp. The axis will never go above this value.
no_padding"top" / "bottom" / "both"Remove automatic 10% padding from edges. Useful when a domain clamp is a hard boundary (e.g. drawdown capped at 0).

If y_axes is omitted, axes are auto-generated based on metric axis values.

Example: Price + Volume with Vertical Zones

Stack volume bars in the bottom 20% and price in the remaining space:

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": [
{"id": "price", "style": "line", "color": "#374151", "y_axis_id": "axis-price"},
{"id": "volume", "style": "bar", "color": "#3b82f6", "fill_opacity": 0.3, "stroke_width": 0, "y_axis_id": "axis-vol"}
],
"y_axes": [
{"id": "axis-price", "side": "right", "scale": "log", "format": "currency", "range": [20, 100]},
{"id": "axis-vol", "side": "left", "format": "number", "range": [0, 20], "no_padding": "bottom"}
],
"days": 365,
"title": "BTC Price + Volume (Zoned)"
}' --output price_volume_zones.png

What this produces:

  • Volume bars fill the bottom 20% of the chart (range: [0, 20]) with no padding at the bottom edge
  • Price occupies the top 80% (range: [20, 100]) on a log scale
  • The two series never overlap, creating a clean stacked layout

Example: Drawdown with Domain Clamp

Cap drawdown at 0 (top edge) so the line touches the top of its zone:

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": ["price"],
"formulas": [
{"expression": "drawdown(price)", "label": "Drawdown from ATH", "style": "area", "color": "#dc2626", "fill_opacity": 0.15, "y_axis_id": "axis-dd"}
],
"y_axes": [
{"id": "axis-right", "side": "right", "scale": "log", "format": "currency"},
{"id": "axis-dd", "side": "left", "format": "percent", "domain_max": 0, "no_padding": "top"}
],
"days": 1825,
"title": "BTC Price + Drawdown from ATH"
}' --output drawdown.png

What this produces:

  • Drawdown is always ≤ 0, so domain_max: 0 clamps the top edge
  • no_padding: "top" removes the automatic 10% padding above 0, making the line touch the top when drawdown is 0%
  • Price is on the right axis with log scale

Formulas

The formulas field lets you define computed series derived from your metrics. Formulas can reference metrics by their id (e.g. lth_supply) or by positional index (m1, m2, etc. based on order in the metrics array).

"formulas": [
{
"expression": "lth_supply - shift(lth_supply, 30)",
"label": "LTH 30d Change",
"color": "#16a34a",
"style": "bar",
"y_axis_id": "axis-diff",
"fill_opacity": 0.2,
"stroke_width": 0
}
]

Supported functions (30 total):

Moving Averages & Rolling Statistics

FunctionSyntaxDescription
smasma(series, period)Simple Moving Average
emaema(series, period)Exponential Moving Average
medianmedian(series, period)Rolling median
sumsum(series, period)Rolling sum
stdstd(series, period)Rolling standard deviation

Cumulative

FunctionSyntaxDescription
cumsumcumsum(series)Expanding cumulative sum
cummeancummean(series)Expanding cumulative mean
cummediancummedian(series)Expanding cumulative median
cumstdcumstd(series)Expanding cumulative std dev
cummaxcummax(series)All-time cumulative max
cummincummin(series)All-time cumulative min

Changes

FunctionSyntaxDescription
percent_changepercent_change(series, period)Percentage change (decimal: 0.20 = +20%)
diffdiff(series, period)Absolute value change

Math

FunctionSyntaxDescription
absabs(series)Absolute value
powpow(series, n)Raise to power n
loglog(series)Base-10 logarithm
roundround(series, digits)Round to N decimal places
maxmax(a, b, ...)Pointwise maximum
minmin(a, b, ...)Pointwise minimum

Technical Indicators

FunctionSyntaxDescription
rsirsi(series, period)Relative Strength Index (0-100)
corrcorr(s1, s2, period)Pearson correlation (-1 to 1)
drawdowndrawdown(series)Drawdown from ATH (negative decimal)

Risk & Return

FunctionSyntaxDescription
mean_returnmean_return(series, period)Annualized rolling mean return
realized_volrealized_vol(series, period)Annualized realized volatility
sharpe_ratio_arithmeticsharpe_ratio_arithmetic(series, period)Sharpe ratio (arithmetic)
sharpe_ratio_geometricsharpe_ratio_geometric(series, period)Sharpe ratio (geometric)

Series Manipulation

FunctionSyntaxDescription
shiftshift(series, period)Shift series by N periods
ifif(a, "op", b, then, else)Conditional (op: =, !=, >, >=, <, <=)

Operators

Arithmetic: +, -, *, / Grouping: (, )

Referencing

  • Metrics by name: lth_supply + sth_supply — use metric IDs directly
  • Metrics by position: m1 + m2 — positional references (m1 = first metric, m2 = second, etc.)
  • Other formulas: f1 * 2 — reference earlier formulas (f1 = first formula, etc.)
  • Formulas are evaluated in order, so f2 can reference f1, but not vice versa.

Formula options:

FieldTypeDescription
expressionstringRequired. Formula expression using metric IDs or positional refs (m1, m2).
labelstringRequired. Display label for the legend.
colorstringHex color. Auto-assigned if omitted.
styleline / area / barChart style. Default: line.
y_axis_idstringBind to a specific Y-axis by ID (e.g. axis-diff). Overrides axis.
axisleft / rightY-axis side. Default: left. Ignored if y_axis_id is set.
fill_opacityfloatFill opacity (0.0-1.0). For transparent bars, use low values like 0.2.
stroke_widthintegerStroke width (0-5). Use 0 for bars without borders.
stroke_dashstringDash pattern (e.g., 6 3).
stack_groupstringStack group ID for stacking multiple formula series.

Reference Lines & Areas

Reference lines add horizontal guide lines to highlight specific values (e.g. break-even at 1.0, overbought threshold). Reference areas add shaded zones to highlight value ranges (e.g. undervalued zone, Bollinger-like bands). Both support static values and dynamic formulas using the same formula engine as the formulas field.

Reference Line Options

FieldTypeDescription
ynumberStatic Y value.
y_formulastringFormula expression for dynamic Y (e.g. "sma(m1, 200)"). Uses the same engine as formulas.
y_axis_idstringY-axis ID (defaults to first left axis).
strokestringLine color hex (default: #9ca3af).
stroke_dasharraystringDash pattern, e.g. "3 3" for dashed.
labelstringLabel text.

Provide either y (static) or y_formula (dynamic), not both. Maximum 10 reference lines per chart.

Reference Area Options

FieldTypeDescription
y1numberStatic lower Y bound.
y2numberStatic upper Y bound.
y1_formulastringFormula for dynamic lower bound.
y2_formulastringFormula for dynamic upper bound.
y_axis_idstringY-axis ID (defaults to first left axis).
fillstringFill color hex (default: #3b82f6).
fill_opacitynumberFill opacity 0–1 (default: 0.1).
labelstringLabel text.

Provide static (y1/y2) or formula-based (y1_formula/y2_formula) bounds — you can mix them (e.g. static y1 with dynamic y2_formula). Maximum 10 reference areas per chart.

Example: MVRV with Value Zones

Add green undervalued zone (0–0.85), red overvalued zone (8–100), and a dashed break-even line at 1.0:

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metric": "mvrv",
"days": 1825,
"title": "MVRV Ratio — Value Zones",
"reference_lines": [
{"y": 1.0, "stroke": "#9ca3af", "stroke_dasharray": "3 3", "label": "Break-even"}
],
"reference_areas": [
{"y1": 0, "y2": 0.85, "fill": "#16a34a", "fill_opacity": 0.08, "label": "Undervalued"},
{"y1": 8, "y2": 100, "fill": "#dc2626", "fill_opacity": 0.08, "label": "Overvalued"}
]
}' --output mvrv_zones.png

Example: Formula-Based Band

Create a Bollinger-like band around the first formula (±10% envelope):

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": ["price"],
"days": 365,
"formulas": [
{"expression": "sma(m1, 50)", "label": "50-day SMA", "color": "#2563eb", "style": "line"}
],
"reference_areas": [
{"y1_formula": "f1 * 0.9", "y2_formula": "f1 * 1.1", "fill": "#2563eb", "fill_opacity": 0.06, "label": "±10% Band"}
],
"reference_lines": [
{"y_formula": "sma(m1, 200)", "stroke": "#9333ea", "stroke_dasharray": "6 3", "label": "200-day SMA"}
]
}' --output price_bands.png

Output Format

The format field controls the output:

FormatContent-TypeDescription
png (default)image/pngRasterized chart image
svgimage/svg+xmlVector graphics (scalable, embeddable)
jsonapplication/jsonChart metadata (no rendering)

Alternatively, use the Accept header:

  • Accept: image/png - PNG (default)
  • Accept: image/svg+xml - SVG
  • Accept: application/json - JSON metadata

JSON Metadata Response

When format=json or Accept: application/json:

{
"success": true,
"title": "BTC Price",
"metrics": [{"id": "price", "label": "BTC Price"}],
"days": 365,
"start_date": null,
"end_date": null,
"theme": "light",
"width": 1200,
"height": 600,
"formulas": [],
"data_points": 365,
"cached": false,
"render_time_ms": 0
}

Examples

# POST with single metric
curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"metric": "price", "days": 365}' \
--output price.png

# Multi-metric with custom styling
curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": [
{"id": "price", "axis": "right", "style": "line", "color": "#374151"},
{"id": "lth_supply", "axis": "left", "style": "area", "color": "#2563eb"}
],
"days": 730,
"title": "BTC Price vs LTH Supply",
"theme": "dark"
}' \
--output chart.png

# SVG output
curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"template": "mvrv_ratio", "format": "svg"}' \
--output mvrv.svg

# JSON metadata
curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"metric": "price", "format": "json"}' | jq

Heatmap Rendering

The Snapshot API can render heatmap charts for distribution-based metrics like Cost Basis Distribution. Heatmaps use a separate set of parameters from standard metric charts.

Heatmap Parameters

ParameterTypeDefaultDescription
heatmap_idstring-Heatmap identifier (e.g., cost-basis-distribution)
heatmap_periodstring1yTime period: 3m, 6m, 1y, 2y, 3y, 5y, all
heatmap_color_scalestringviridisColor scale: viridis, plasma, inferno, magma, cividis
heatmap_y_scalestringlinearY-axis scale: linear or log
themestringlightColor theme: light or dark
titlestringautoChart title
widthinteger1200Image width in pixels
heightinteger600Image height in pixels

Example

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"heatmap_id": "cost-basis-distribution",
"heatmap_period": "1y",
"heatmap_color_scale": "viridis",
"heatmap_y_scale": "log",
"theme": "dark",
"title": "Cost Basis Distribution"
}' --output cbd_heatmap.png

Note: Heatmap parameters (heatmap_id, etc.) are mutually exclusive with standard metric parameters (metric, metrics, template). Heatmap metrics require Enterprise tier.

The color scale legend is included in the rendered image, showing the value range mapped to the selected color palette.


Cycle Performance Overlay Charts

Use x_axis: "day_offset" to render cycle performance overlay charts where all Bitcoin halving cycles are aligned to Day 0 for comparison.

x_axis Parameter

ValueDescription
date (default)Standard date-based X axis
day_offsetDays since cycle start (Day 0, Day 100, etc.). All cycles overlay on the same axis for comparison.

Example

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metric": "cycle_performance",
"x_axis": "day_offset",
"title": "BTC Cycle Performance Comparison",
"theme": "dark",
"scale": "log"
}' --output cycle_overlay.png

Per-Metric Legend Control

Use show_in_legend on individual metric config objects to control whether a metric appears in the chart legend. This is useful when combining many series where some are context/background lines.

{
"metrics": [
{"id": "price", "show_in_legend": true},
{"id": "sma_200", "show_in_legend": false}
]
}
FieldTypeDefaultDescription
show_in_legendbooleantrueWhether the metric appears in the chart legend

Smart Defaults

The Snapshot API uses intelligent defaults so you can get great-looking charts with minimal configuration:

ParameterHow Default Is Determined
Chart styleFrom metric registry (chart_types[0])
ColorFrom metric registry, then palette rotation
Y-axis sideFirst metric on left; same-format metrics share axis; different format on right
Y-axis scalelinear (override with scale=log)
Time rangeCategory-based: 365 days for price/valuation/profit, 730 for supply, 180 for blockchain
TitleSingle metric: metric name. Multiple: "Name1 vs Name2"
Image size1200 x 600 pixels
Themelight

Error Responses

All errors return JSON:

// 400 Bad Request
{"success": false, "error": "invalid_params", "message": "Exactly one of 'metric', 'metrics', or 'template' must be provided"}

// 401 Unauthorized
{"success": false, "error": "unauthorized", "message": "API key required"}

// 403 Forbidden
{"success": false, "error": "insufficient_tier", "message": "Metric 'lth_sopr' requires Pro tier", "upgrade_url": "https://blocklens.co/pricing"}

// 429 Rate Limited
{"success": false, "error": "rate_limited", "message": "Snapshot rate limit exceeded. Max 60 per hour for pro tier.", "retry_after": 120}

// 504 Timeout
{"success": false, "error": "render_timeout", "message": "Chart rendering timed out after 20.0s. Try a shorter date range."}

MCP Tool: render_chart

The Blocklens MCP server includes a render_chart tool that lets AI agents generate chart images directly in conversations. The tool calls the Snapshot API and returns the image inline.

Parameters

ParameterTypeDefaultDescription
metricstring-Single metric ID
metricsarray-Multiple metrics (strings or objects)
templatestring-Template ID
daysinteger365Days of history
start_datestring-Start date (YYYY-MM-DD)
end_datestring-End date (YYYY-MM-DD)
overlayprice-Add price overlay (currently BTC)
themelight / darklightColor theme
widthinteger1200Image width
heightinteger600Image height
titlestringautoChart title
styleline / area / barautoChart style
scalelinear / loglinearY-axis scale
formatpng / jsonpngOutput format
y_axesarray-Custom Y-axes with zones (see Custom Y-Axes)
reference_linesarray-Horizontal reference lines (see Reference Lines & Areas)
reference_areasarray-Shaded reference zones (see Reference Lines & Areas)

Usage Examples

User: "Show me the MVRV ratio for the last 2 years"
Agent calls: render_chart({ template: "mvrv_ratio", days: 730 })
-> Returns PNG image inline

User: "Chart BTC price vs LTH supply"
Agent calls: render_chart({
metrics: [
{ id: "price", axis: "right" },
{ id: "lth_supply", axis: "left", style: "area" }
],
days: 365
})
-> Returns PNG image inline

User: "Is there capitulation? Show SOPR"
Agent calls: render_chart({ template: "sopr", days: 180, overlay: "price" })
-> Returns PNG image inline

MCP Configuration

Add to your Claude Desktop or Cursor config to enable chart rendering:

{
"mcpServers": {
"blocklens": {
"command": "npx",
"args": ["-y", "blocklens-mcp-server"],
"env": {
"BLOCKLENS_API_KEY": "your_api_key_here"
}
}
}
}

See MCP Server for full setup instructions.


Advanced Example: LTH Supply Chart

This example replicates the full Long-Term Holder Supply chart from the Blocklens dashboard — two metrics, two computed formula series, and three Y-axes:

curl -X POST "https://api.blocklens.co/v1/chart/snapshot" \
-H "Authorization: Bearer YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"metrics": [
{"id": "price", "label": "BTC Price", "style": "line", "color": "#6b7280", "axis": "right", "fill_opacity": 0, "stroke_width": 1},
{"id": "lth_supply", "label": "LTH Supply", "style": "line", "color": "#2563eb", "axis": "left", "stroke_width": 2}
],
"y_axes": [
{"id": "axis-left", "side": "left", "scale": "linear"},
{"id": "axis-right", "side": "right", "scale": "log"},
{"id": "axis-diff", "side": "left", "scale": "linear"}
],
"formulas": [
{"expression": "max(lth_supply - shift(lth_supply, 30), 0)", "label": "LTH 30d+ diff", "color": "#16a34a", "style": "bar", "y_axis_id": "axis-diff", "fill_opacity": 0.2, "stroke_width": 0},
{"expression": "min(0, lth_supply - shift(lth_supply, 30))", "label": "LTH 30d- diff", "color": "#dc2626", "style": "bar", "y_axis_id": "axis-diff", "fill_opacity": 0.2, "stroke_width": 0}
],
"days": 730,
"title": "Long-Term Holder Supply"
}' --output lth_supply.png

What this produces:

  • BTC Price — gray line on the right axis (log scale)
  • LTH Supply — blue line on the left axis (linear)
  • 30-day positive accumulation — semi-transparent green bars on a separate axis-diff axis
  • 30-day distribution — semi-transparent red bars on the same axis-diff axis

Key techniques used:

  • shift(lth_supply, 30) computes the 30-day lookback value
  • max(..., 0) and min(0, ...) split positive and negative changes into separate series
  • y_axis_id: "axis-diff" binds both formula bars to a dedicated axis independent of the main metric axes
  • fill_opacity: 0.2 + stroke_width: 0 creates subtle, borderless transparent bars

Chart Templates

Full chart configurations (including metrics, formulas, axes, and styling) are available as database-backed templates via:

GET /api/lab/templates

These templates can serve as reference for building your own POST request bodies. Each template contains the complete config that produces a specific chart on the Blocklens dashboard.


Watermark

All rendered chart images include a blocklens.co watermark and copyright notice. This applies to both PNG and SVG output formats.


Caching

Rendered snapshots are cached for 1 hour in Redis. Cache behavior:

  • Identical chart configurations return cached results instantly
  • Cache key is derived from the full chart config (metrics, axes, time range, theme, size)
  • The X-Snapshot-Cache response header indicates HIT or MISS
  • The X-Snapshot-Render-Ms header shows render time (0 for cache hits)
  • Popular charts are pre-warmed after each daily data update (05:00 UTC)