If a Python script can count it, it can chart it. Output Charts draws each visual from a JSON document, and the API lets your code replace that document whenever the numbers change. There is no SDK to install: one HTTP request per chart is the whole integration.
This guide builds two pushes: a KPI with today's total, and a line chart with the last seven days.
Before you start
You need a Solo plan (API push is part of Solo), a dashboard with a KPI and a line chart on it, and an API key from Account → API keys. The key starts with oc_live_ and is shown once.
For each visual, open the editor, select it, and choose Copy push URL under Push from code. Put the key and the two URLs in environment variables, so none of them end up in your code:
export OC_KEY="oc_live_..."
export OC_TOTAL_URL="https://api.outputcharts.com/visuals/<kpi-visual-id>/data"
export OC_TREND_URL="https://api.outputcharts.com/visuals/<line-visual-id>/data"
The examples use requests (pip install requests).
A small push function
import os
import requests
OC_KEY = os.environ["OC_KEY"]
def push(url, document):
"""Replace a visual's JSON document. Raises with the API's own message on failure."""
response = requests.put(
url,
json=document,
headers={"Authorization": f"Bearer {OC_KEY}"},
timeout=10,
)
if response.status_code == 422:
problems = response.json().get("details", [])
raise ValueError(f"Document rejected: {problems}")
response.raise_for_status()
return response.json()
json= serializes the document and sets the Content-Type header. A successful push returns the visual's id and the time of the change.
Push a number
A KPI needs a label, a number, and a format. delta and deltaLabel are optional and show the change next to it:
total = 214 # whatever your script computed
yesterday = 187
push(os.environ["OC_TOTAL_URL"], {
"label": "Orders today",
"value": total,
"format": "number",
"delta": total - yesterday,
"deltaFormat": "number",
"deltaLabel": "vs yesterday",
})
Push a chart
A line chart takes the key for the x axis, the series to draw, and one row per point. Each row has exactly the x key and the series keys, and x values are strings:
daily = [("Mon", 41), ("Tue", 57), ("Wed", 49), ("Thu", 63), ("Fri", 70), ("Sat", 38), ("Sun", 35)]
push(os.environ["OC_TREND_URL"], {
"xKey": "day",
"curve": "monotone",
"series": [{"key": "signups", "label": "Signups"}],
"data": [{"day": day, "signups": count} for day, count in daily],
})
In a real script, daily comes from a database query or another API. If your x values are dates, send them as strings, such as "2026-10-18".
Open copies of the dashboard check for new data every 15 seconds, so both visuals update on every screen shortly after the script runs.
Errors worth handling
422 invalid_document: the document does not fit the visual's type. Thedetailslist names each wrong field, for example{"path": "data[3].signups", "message": "Expected number"}. ANonefrom a query is the usual cause.429 rate_limited: one key can push 60 times a minute. Push once per visual per run rather than in a tight loop.401 invalid_api_key: the key is wrong or revoked. A brand-new key can also need a few seconds.403 requires_solo: the account is on Free. Keys pause and work again after an upgrade.
Each push replaces the whole document, so always send the full set of rows. Documents can be up to 100 KB.
Run it on a schedule
A script like this is most useful when it runs by itself: from cron, a scheduled cloud function, or a CI job. Whatever runs it needs only OC_KEY and the push URLs.
To try document shapes before writing code, paste them into JSON to chart. Create a free account to build the dashboard; Solo turns on API keys.