Code Examples
curl, Python (requests) and JavaScript (Node 18 or later, as an ES module) for every operation an API key, or no credential at all, can call. Create a key on the API Keys page and export it as GATIFLOW_API_KEY. The Daily Insights payload is not here: it needs the web session, and a key receives 401 there.
The same requests as a Postman collection: /postman_collection.json. The response shapes are in the contract.
Current intelligence report
GET /api/v1/intelligence/report · X-API-Key
Pass schema_version=1.2 for the full contract block. One call consumes one unit of the daily quota; X-DailyQuota-Remaining says what is left.
curl
curl -s -H "X-API-Key: $GATIFLOW_API_KEY" \ "https://api.gatiflow.io/api/v1/intelligence/report?schema_version=1.2"
Python
import os
import requests
response = requests.get(
"https://api.gatiflow.io/api/v1/intelligence/report",
headers={"X-API-Key": os.environ["GATIFLOW_API_KEY"]},
params={"schema_version": "1.2"},
timeout=30,
)
response.raise_for_status()
report = response.json()
for signal in report["sections"]["market_trends"]["data"]:
print(signal["title"], signal.get("confidence"))
print("calls left today:", response.headers.get("X-DailyQuota-Remaining"))JavaScript
const response = await fetch(
"https://api.gatiflow.io/api/v1/intelligence/report?schema_version=1.2",
{ headers: { "X-API-Key": process.env.GATIFLOW_API_KEY } },
);
if (!response.ok) throw new Error(`${response.status} ${JSON.stringify(await response.json())}`);
const report = await response.json();
for (const signal of report.sections.market_trends.data) {
console.log(signal.title, signal.confidence);
}Export the report as CSV
GET /api/v1/intelligence/report/export · X-API-Key
CSV on Pro, CSV or PDF on Business. Starter receives 403. The body is the file itself.
curl
curl -s -H "X-API-Key: $GATIFLOW_API_KEY" -o gatiflow-report.csv \ "https://api.gatiflow.io/api/v1/intelligence/report/export?format=csv"
Python
import os
import requests
response = requests.get(
"https://api.gatiflow.io/api/v1/intelligence/report/export",
headers={"X-API-Key": os.environ["GATIFLOW_API_KEY"]},
params={"format": "csv"},
timeout=60,
)
response.raise_for_status()
with open("gatiflow-report.csv", "wb") as file:
file.write(response.content)JavaScript
import { writeFile } from "node:fs/promises";
const response = await fetch(
"https://api.gatiflow.io/api/v1/intelligence/report/export?format=csv",
{ headers: { "X-API-Key": process.env.GATIFLOW_API_KEY } },
);
if (!response.ok) throw new Error(`${response.status} ${JSON.stringify(await response.json())}`);
await writeFile("gatiflow-report.csv", Buffer.from(await response.arrayBuffer()));List retained snapshots
GET /api/v1/intelligence/report-history · X-API-Key
Newest first, 1 to 50 per call. Retention follows the plan; an expired trial receives an empty list.
curl
curl -s -H "X-API-Key: $GATIFLOW_API_KEY" \ "https://api.gatiflow.io/api/v1/intelligence/report-history?limit=5"
Python
import os
import requests
response = requests.get(
"https://api.gatiflow.io/api/v1/intelligence/report-history",
headers={"X-API-Key": os.environ["GATIFLOW_API_KEY"]},
params={"limit": 5},
timeout=30,
)
response.raise_for_status()
for snapshot in response.json()["snapshots"]:
print(snapshot["snapshot_id"], snapshot["signal_count"])JavaScript
const response = await fetch(
"https://api.gatiflow.io/api/v1/intelligence/report-history?limit=5",
{ headers: { "X-API-Key": process.env.GATIFLOW_API_KEY } },
);
if (!response.ok) throw new Error(`${response.status} ${JSON.stringify(await response.json())}`);
const { snapshots } = await response.json();
for (const snapshot of snapshots) console.log(snapshot.snapshot_id, snapshot.signal_count);Read one archived snapshot
GET /api/v1/intelligence/report/at/{snapshot_id} · X-API-Key
snapshot_id comes from the history list, in the YYYYMMDDTHHmm format. Consumes no daily quota.
curl
curl -s -H "X-API-Key: $GATIFLOW_API_KEY" \ "https://api.gatiflow.io/api/v1/intelligence/report/at/20260926T0600"
Python
import os
import requests
snapshot_id = "20260926T0600" # from report-history
response = requests.get(
f"https://api.gatiflow.io/api/v1/intelligence/report/at/{snapshot_id}",
headers={"X-API-Key": os.environ["GATIFLOW_API_KEY"]},
timeout=30,
)
response.raise_for_status()
print(response.json()["generated_at"])JavaScript
const snapshotId = "20260926T0600"; // from report-history
const response = await fetch(
`https://api.gatiflow.io/api/v1/intelligence/report/at/${snapshotId}`,
{ headers: { "X-API-Key": process.env.GATIFLOW_API_KEY } },
);
if (!response.ok) throw new Error(`${response.status} ${JSON.stringify(await response.json())}`);
console.log((await response.json()).generated_at);Calls made with this key
GET /api/v1/usage · X-API-Key
The log of the key on the request, newest first. The default is 100 events and the maximum 500.
curl
curl -s -H "X-API-Key: $GATIFLOW_API_KEY" \ "https://api.gatiflow.io/api/v1/usage?limit=20"
Python
import os
import requests
response = requests.get(
"https://api.gatiflow.io/api/v1/usage",
headers={"X-API-Key": os.environ["GATIFLOW_API_KEY"]},
params={"limit": 20},
timeout=30,
)
response.raise_for_status()
for event in response.json()["usage"]:
print(event["timestamp"], event["status_code"], event["endpoint"])JavaScript
const response = await fetch("https://api.gatiflow.io/api/v1/usage?limit=20", {
headers: { "X-API-Key": process.env.GATIFLOW_API_KEY },
});
if (!response.ok) throw new Error(`${response.status} ${JSON.stringify(await response.json())}`);
for (const event of (await response.json()).usage) {
console.log(event.timestamp, event.status_code, event.endpoint);
}Latest Deep Dive preview
GET /api/v1/public/deep-dive · no credential
No credential. Capped at 60 requests a minute per caller address; the article changes once a week.
curl
curl -s "https://api.gatiflow.io/api/v1/public/deep-dive"
Python
import requests
response = requests.get("https://api.gatiflow.io/api/v1/public/deep-dive", timeout=30)
response.raise_for_status()
preview = response.json()
print(preview["title"] if preview["status"] == "ok" else preview["message"])JavaScript
const response = await fetch("https://api.gatiflow.io/api/v1/public/deep-dive");
if (!response.ok) throw new Error(`${response.status}`);
const preview = await response.json();
console.log(preview.status === "ok" ? preview.title : preview.message);Handling 429 and 503
Every error arrives in the same envelope, with the reason in error.message. A 429 reading Rate limit exceeded clears when the one-minute window passes; Daily quota exceeded does not. A 503 on the report or the export means the underlying data is older than 24 hours, and Retry-After says when to ask again.
import os
import time
import requests
def get_report(attempts=3):
url = "https://api.gatiflow.io/api/v1/intelligence/report"
headers = {"X-API-Key": os.environ["GATIFLOW_API_KEY"]}
for _ in range(attempts):
response = requests.get(url, headers=headers, timeout=30)
if response.status_code == 429 and response.json()["error"]["message"] == "Rate limit exceeded":
time.sleep(60) # the per-minute window
continue
if response.status_code == 503:
retry_after = response.headers.get("Retry-After")
raise RuntimeError(f"data older than 24 hours; ask again in {retry_after} seconds")
response.raise_for_status() # includes 429 "Daily quota exceeded"
return response.json()
raise RuntimeError(f"still rate limited after {attempts} attempts")