← API Documentation

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")