Tarot API

The full 78-card Rider-Waite-Smith encyclopedia as JSON, server-side spread draws, and optional AI interpretation — all behind one Bearer token.

Authentication

Every account has an API token — it's on your account page. Send it as a Bearer header on every request.

Create a free account to get your token

The deck

Free with any account. Card copy is returned in your requested language — pass ?lang= with any of the 100 supported ISO codes.

curl -s "https://tarot.free/api/v1/cards/?arcana=major" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

curl -s "https://tarot.free/api/v1/cards/the-tower/?lang=es" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

curl -s https://tarot.free/api/v1/spreads/ \
  -H "Authorization: Bearer YOUR_API_TOKEN"
{
  "ok": true, "lang": "en", "count": 22,
  "cards": [
    {"slug": "the-fool", "name": "The Fool", "number": 0,
     "arcana": "major", "suit": "", "yes_no": "yes",
     "keywords_upright": ["beginnings", "innocence", "leap of faith"],
     "keywords_reversed": ["recklessness", "hesitation"],
     "image": "/static/cards/the-fool.webp",
     "url": "https://tarot.free/cards/the-fool/"}
  ]
}

Draw a reading

The draw happens server-side — cards are sampled without replacement with an independent 50% chance of reversal, so nobody can stack the deck. Set interpret to true to get the AI reading in the same response.

POST https://tarot.free/api/v1/reading/
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json

{
  "spread": "three-card",     // GET /api/v1/spreads/ for the list
  "question": "What should I focus on this month?",
  "interpret": true,          // false = just the draw (free)
  "tier": "deep",             // basic (free) | deep (2) | master (4)
  "lang": "en"
}
{
  "ok": true,
  "token": "9f3c…",
  "url": "https://tarot.free/reading/9f3c…/",
  "spread": "three-card",
  "cards": [
    {"position": 1, "reversed": false, "card": {"slug": "the-star", …}},
    {"position": 2, "reversed": true,  "card": {"slug": "five-of-cups", …}},
    {"position": 3, "reversed": false, "card": {"slug": "the-sun", …}}
  ],
  "interpretation": "…",
  "tier": "deep",
  "credits": 8
}

Python

import requests

H = {"Authorization": "Bearer YOUR_API_TOKEN"}

r = requests.post("https://tarot.free/api/v1/reading/", headers=H,
                  json={"spread": "three-card",
                        "question": "What should I focus on this month?",
                        "interpret": True, "tier": "deep"}).json()

for slot in r["cards"]:
    card = slot["card"]
    print(slot["position"], card["name"],
          "(reversed)" if slot["reversed"] else "")
print(r["interpretation"])

Node.js

const r = await fetch("https://tarot.free/api/v1/reading/", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({spread: "celtic-cross", interpret: false}),
});
const {cards, token} = await r.json();

Re-fetch a reading

curl -s https://tarot.free/api/v1/reading/9f3c…/ \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Errors

Errors come back with ok:false and a code: unauthorized (401), bad_json / bad_spread (400), insufficient_credits (402), not_found (404), rate_limited (429, with retry_after), engine_busy (503). When an interpretation is refused the draw is still saved — top up and re-fetch it by token.

API pricing

The API bills exactly like the site — there is no separate developer plan and no per-request fee.

  • Cards, spreads and un-interpreted draws: free with any account, rate-limited
  • basic reader: free · deep reader: 2 credits · master reader: 4 credits
  • Credits come from the same packs as the site: $3 / $7 / $13, and never expire
See pricing →