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.json

Latest 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.txt

Latest 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.json

Brief 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.txt

Same, 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.json

Bulk: 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.csv

Bulk: 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.json

Freshness: 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.

FieldTypeMeaning
schema_versionstringSchema version of this document.
namestringPublication name.
datestring (YYYY-MM-DD)Brief date, America/New_York.
generated_atstring (ISO 8601 UTC)When this brief was built.
generated_at_etstringSame time in Eastern Time.
urlstring (URL)Permanent URL of this brief edition.
disclaimerstringNot-investment-advice notice. Keep it when relaying.
licensestringUsage and attribution terms.
treasuries.as_ofdateTreasury curve date used.
treasuries.priordateCurve date the changes are measured against.
treasuries.unitstringUnit of the yields.
treasuries.source / source_urlstringPrimary source and link.
treasuries.yields.{tenor}.yieldnumber (%)Par yield for each tenor Treasury publishes (e.g. 1M ... 30Y).
treasuries.yields.{tenor}.chg_bpinteger (bp)Change vs treasuries.prior in basis points.
treasuries.spread_2s10s_bp / _chg_bpinteger (bp)10Y minus 2Y and its change (kept for compatibility).
treasuries.spread_3m10y_bp / _chg_bpinteger (bp)10Y minus 3M and its change (kept for compatibility).
fx.as_ofdateECB reference-rate date used.
fx.priordateECB date the changes are measured against.
fx.basisstringHow rates are derived.
fx.source / source_urlstringPrimary source and link.
fx.pairs.{PAIR}.ratenumberQuote currency per 1 base currency (e.g. USDJPY = yen per dollar).
fx.pairs.{PAIR}.chg_pctnumber (%)Change vs fx.prior, percent.
crypto.as_ofstring (ISO 8601 UTC)Time of the CoinGecko data.
crypto.window / quotestringChange window (rolling 24h) and quote currency (USD).
crypto.source / source_urlstringPrimary source and link.
crypto.assets.{BTC,ETH,SOL}.pricenumber (USD)Spot price.
crypto.assets.{BTC,ETH,SOL}.chg_24h_pctnumber (%)Rolling 24h change.
crypto.assets.{BTC,ETH,SOL}.mcap_usdinteger (USD)Market cap.
crypto.total_mcap_usdinteger (USD)Total crypto market cap.
crypto.total_mcap_chg_24h_pctnumber (%)Total market cap 24h change.
crypto.btc_dominance_pctnumber (%)BTC share of total market cap.
notesstring[]Always empty in a published brief (a failed core source blocks publishing).
basisstringWhat each section's change is measured against.
signalsstring[]Plain-language facts derived from the numbers (no opinions, not signals to trade).
compactstringToken-minimal one-line brief.
compact_tokens_estintegerRough token count of compact (chars/4).

Rules for relaying

Disclaimer: Informational market data only. Not investment advice. Rates may be delayed or revised by the source.