MacroTape API reference
Plain-English guide with copy-paste examples. Base URL https://digest.atlasdynamics.space. GET only, CORS open. Weekdays only: AM edition ~7 AM ET (overnight closes), PM edition ~1 PM ET (refreshed FX and crypto; Treasuries still the prior close). Machine spec: openapi.json. Field paths and units: topics.json.
Authentication
Data endpoints need an API key. Get one instantly on the pricing page (early access, payment comes later). Send it in either header:
Authorization: Bearer mt_xxxxxxxxxxxxxxxx X-API-Key: mt_xxxxxxxxxxxxxxxx
Errors are JSON: 401 = missing or unknown key, 429 = daily limit reached (resets midnight ET). Both include message, signup_url and docs_url. Limits: Early-access trial 100/day, API Light 2,000/day, API Pro 20,000/day.
Open without a key: /api/topics.json, /api/index.json, /openapi.json, /llms.txt, and the HTML pages.
Create a key from code: POST /api/keys with JSON {"email": "...", "plan": "trial|light|pro"}. The key is returned once.
Endpoints
GET /api/latest.jsonLatest brief (newest edition), full JSON.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/latest.json # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/latest.json
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/latest.json", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.json()
const res = await fetch("https://digest.atlasdynamics.space/api/latest.json", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.json();GET /api/latest.txtLatest brief as one compact text line plus as-of times.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/latest.txt # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/latest.txt
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/latest.txt", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.text
const res = await fetch("https://digest.atlasdynamics.space/api/latest.txt", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.text();GET /api/index.json (open, no key)List of every brief and edition with links (no market data).
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/index.json # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/index.json
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/index.json", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.json()
const res = await fetch("https://digest.atlasdynamics.space/api/index.json", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.json();GET /api/briefs/2026-10-17.jsonBrief for a date (YYYY-MM-DD): the newest edition that day. Also /api/briefs/YYYY-MM-DD-am.json and -pm.json.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/briefs/2026-10-17.json # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/briefs/2026-10-17.json
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/briefs/2026-10-17.json", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.json()
const res = await fetch("https://digest.atlasdynamics.space/api/briefs/2026-10-17.json", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.json();GET /api/briefs/2026-10-17.txtSame, compact text. Also -am.txt / -pm.txt.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/briefs/2026-10-17.txt # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/briefs/2026-10-17.txt
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/briefs/2026-10-17.txt", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.text
const res = await fetch("https://digest.atlasdynamics.space/api/briefs/2026-10-17.txt", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.text();GET /api/archive.jsonBulk: every brief, full JSON (research dataset).
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/archive.json # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/archive.json
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/archive.json", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.json()
const res = await fetch("https://digest.atlasdynamics.space/api/archive.json", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.json();GET /api/archive.csvBulk: one row per brief, one column per field.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/archive.csv # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/archive.csv
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/archive.csv", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.text
const res = await fetch("https://digest.atlasdynamics.space/api/archive.csv", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.text();GET /api/changelog.jsonFreshness: each section's as_of, last fetch, and every run including skipped ones.
curl -s -H "Authorization: Bearer $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/changelog.json # or: curl -s -H "X-API-Key: $MACROTAPE_KEY" https://digest.atlasdynamics.space/api/changelog.json
import os, requests
r = requests.get("https://digest.atlasdynamics.space/api/changelog.json", headers={"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}, timeout=20)
r.raise_for_status()
data = r.json()
const res = await fetch("https://digest.atlasdynamics.space/api/changelog.json", { headers: { Authorization: `Bearer ${process.env.MACROTAPE_KEY}` } });
if (!res.ok) throw new Error(`MacroTape ${res.status}: ${await res.text()}`);
const data = await res.json();LLM tool / function-calling example
OpenAI-style tool definition (works the same way in most agent frameworks):
{
"type": "function",
"function": {
"name": "get_macrotape_brief",
"description": "Get the latest MacroTape market brief: U.S. Treasury par curve and spreads, USD FX crosses (ECB reference rates), and crypto (BTC/ETH/SOL, top 20, dominance, stablecoins). Quote each section's as_of and say it is not investment advice.",
"parameters": {
"type": "object",
"properties": {
"format": {
"type": "string",
"enum": [
"json",
"text"
],
"description": "json = full structured brief; text = one compact line."
},
"date": {
"type": "string",
"description": "Optional YYYY-MM-DD for a past brief; omit for the latest."
},
"edition": {
"type": "string",
"enum": [
"am",
"pm"
],
"description": "Optional edition for a dated brief."
}
},
"required": []
}
}
}
Handler your agent runs when the model calls the tool:
import os, requests
BASE = "https://digest.atlasdynamics.space"
H = {"Authorization": f"Bearer {os.environ['MACROTAPE_KEY']}"}
def get_macrotape_brief(format="json", date=None, edition=None):
ext = "txt" if format == "text" else "json"
path = f"/api/briefs/{date}{'-' + edition if edition else ''}.{ext}" if date else f"/api/latest.{ext}"
r = requests.get(BASE + path, headers=H, timeout=20)
if r.status_code in (401, 429): return r.json() # message + signup_url, pass to the user
r.raise_for_status()
return r.text if ext == "txt" else r.json()
Field-by-field (latest.json)
Generated from the live latest.json; every row below exists in today's document. From the first editioned brief onward (Mon Oct 19, 2026) each brief also carries edition (am|pm), edition_note, and the deeper curve/FX/crypto fields.
| Field | Type | Meaning |
|---|---|---|
schema_version | string | Schema version of this document. |
name | string | Publication name. |
date | string (YYYY-MM-DD) | Brief date, America/New_York. |
generated_at | string (ISO 8601 UTC) | When this brief was built. |
generated_at_et | string | Same time in Eastern Time. |
url | string (URL) | Permanent URL of this brief edition. |
disclaimer | string | Not-investment-advice notice. Keep it when relaying. |
license | string | Usage and attribution terms. |
treasuries.as_of | date | Treasury curve date used. |
treasuries.prior | date | Curve date the changes are measured against. |
treasuries.unit | string | Unit of the yields. |
treasuries.source / source_url | string | Primary source and link. |
treasuries.yields.{tenor}.yield | number (%) | Par yield for each tenor Treasury publishes (e.g. 1M ... 30Y). |
treasuries.yields.{tenor}.chg_bp | integer (bp) | Change vs treasuries.prior in basis points. |
treasuries.spread_2s10s_bp / _chg_bp | integer (bp) | 10Y minus 2Y and its change (kept for compatibility). |
treasuries.spread_3m10y_bp / _chg_bp | integer (bp) | 10Y minus 3M and its change (kept for compatibility). |
fx.as_of | date | ECB reference-rate date used. |
fx.prior | date | ECB date the changes are measured against. |
fx.basis | string | How rates are derived. |
fx.source / source_url | string | Primary source and link. |
fx.pairs.{PAIR}.rate | number | Quote currency per 1 base currency (e.g. USDJPY = yen per dollar). |
fx.pairs.{PAIR}.chg_pct | number (%) | Change vs fx.prior, percent. |
crypto.as_of | string (ISO 8601 UTC) | Time of the CoinGecko data. |
crypto.window / quote | string | Change window (rolling 24h) and quote currency (USD). |
crypto.source / source_url | string | Primary source and link. |
crypto.assets.{BTC,ETH,SOL}.price | number (USD) | Spot price. |
crypto.assets.{BTC,ETH,SOL}.chg_24h_pct | number (%) | Rolling 24h change. |
crypto.assets.{BTC,ETH,SOL}.mcap_usd | integer (USD) | Market cap. |
crypto.total_mcap_usd | integer (USD) | Total crypto market cap. |
crypto.total_mcap_chg_24h_pct | number (%) | Total market cap 24h change. |
crypto.btc_dominance_pct | number (%) | BTC share of total market cap. |
notes | string[] | Always empty in a published brief (a failed core source blocks publishing). |
basis | string | What each section's change is measured against. |
signals | string[] | Plain-language facts derived from the numbers (no opinions, not signals to trade). |
compact | string | Token-minimal one-line brief. |
compact_tokens_est | integer | Rough token count of compact (chars/4). |
Rules for relaying
- Quote numbers with their section's
as_of; Treasuries, FX and crypto can differ. - Attribute to "MacroTape (https://digest.atlasdynamics.space)" and keep the not-investment-advice note.
Disclaimer: Informational market data only. Not investment advice. Rates may be delayed or revised by the source.