Ship a three-mode tarot app (daily card, three-card spread, yes-no oracle) with card imagery and reversed handling. Time to ship: 30 minutes.
Tarot is the highest-frequency divination surface RoxyAPI ships. This tutorial wires the three most-popular features: daily card for daily active users, three-card for the entry reading, yes-no for impulse queries. One HTML file, card imagery included. Then upgrade to <roxy-tarot-card> / <roxy-tarot-spread> for a drop-in renderer.
What you can build
Daily tarot widgets for wellness and lifestyle apps
Three independent calls, same shape. Verified operationIds: getDailyCard, castThreeCard, castYesNo, castCelticCross.
bash
# Daily card
curl -X POST https://roxyapi.com/api/v2/tarot/daily \
-H "X-API-Key: $ROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"seed":"user-42"}'
# Three-card spread
curl -X POST https://roxyapi.com/api/v2/tarot/spreads/three-card \
-H "X-API-Key: $ROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question":"what should I focus on this week"}'
# Yes or no
curl -X POST https://roxyapi.com/api/v2/tarot/yes-no \
-H "X-API-Key: $ROXY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question":"should I take the job"}'
typescript
import { createRoxy } from '@roxyapi/sdk';
const roxy = createRoxy(process.env.ROXY_API_KEY!);
const { data: daily, error: dailyError } = await roxy.tarot.getDailyCard({ body: { seed: 'user-42' } });
if (dailyError) throw dailyError;
console.log(daily.card.name, daily.card.imageUrl);
const { data: spread, error: spreadError } = await roxy.tarot.castThreeCard({
body: { question: 'what should I focus on this week' },
});
if (spreadError) throw spreadError;
spread.positions.forEach(p => console.log(p.name, p.card.name));
const { data: yn, error: ynError } = await roxy.tarot.castYesNo({
body: { question: 'should I take the job' },
});
if (ynError) throw ynError;
console.log(yn.answer); // "Yes" | "No" | "Maybe"
python
import os
from roxy_sdk import create_roxy
roxy = create_roxy(os.environ['ROXY_API_KEY'])
daily = roxy.tarot.get_daily_card(seed='user-42')
print(daily['card']['name'])
spread = roxy.tarot.cast_three_card(question='what should I focus on this week')
for p in spread['positions']:
print(p['name'], p['card']['name'])
yn = roxy.tarot.cast_yes_no(question='should I take the job')
print(yn['answer'])
php
<?php
use function RoxyAPI\Sdk\createRoxy;
$roxy = createRoxy(getenv('ROXY_API_KEY'));
$daily = $roxy->tarot->getDailyCard(seed: 'user-42');
echo $daily['card']['name'];
$spread = $roxy->tarot->castThreeCard(question: 'what should I focus on this week');
foreach ($spread['positions'] as $p) {
echo $p['name'], ' ', $p['card']['name'], "\n";
}
$yn = $roxy->tarot->castYesNo(question: 'should I take the job');
echo $yn['answer'];
csharp
using RoxyApi;
var roxy = new RoxyClient(Environment.GetEnvironmentVariable("ROXY_API_KEY")!);
var daily = await roxy.Tarot.Daily.PostAsync(new() { Seed = "user-42" });
Console.WriteLine($"{daily!.Card!.Name} {daily.Card.ImageUrl}");
var spread = await roxy.Tarot.Spreads.ThreeCard.PostAsync(new() { Question = "what should I focus on this week" });
foreach (var p in spread!.Positions!)
Console.WriteLine($"{p.Name} {p.Card!.Name}");
var yn = await roxy.Tarot.YesNo.PostAsync(new() { Question = "should I take the job" });
Console.WriteLine(yn!.Answer); // "Yes" | "No" | "Maybe"
bash
claude mcp add-json --scope user roxy-tarot '{"type":"http","url":"https://roxyapi.com/mcp/tarot","headers":{"X-API-Key":"YOUR_KEY"}}'
Then ask any MCP client: "draw a daily tarot card for user 42" or "cast a three-card spread for me about my career." Full setup for Cursor, Claude Desktop, Antigravity, and other clients: MCP guide.
Render the result
Option A: drop-in web components
<roxy-tarot-card> renders a single card. <roxy-tarot-spread> renders any spread (three-card, celtic-cross, love, yes-no, draw).
Both components handle reversed cards (image flip), keywords, meanings, and per-position labels for spreads. Theme via CSS custom properties.
Option B: three-mode app, components do the render
Same single file with tabs and one Draw button, but the components handle every card. The vanilla JS only switches mode, calls the endpoint, and assigns the unwrapped response to <roxy-tarot-card> (daily) or <roxy-tarot-spread> (three-card, yes-no) via Pattern 1 from the UI components page. No hand-built card markup, no reversed-flip CSS to maintain: the components own all of it.
<roxy-tarot-card> renders the daily card with reversed flip, keywords, and message. <roxy-tarot-spread> renders the three-card positions and the yes-no answer with its interpretation: set spread to match the response (three-card, yes-no, celtic-cross, love, draw). Theme both with CSS custom properties.
Add Celtic Cross
One more endpoint, same shape: POST /tarot/spreads/celtic-cross (castCelticCross). Returns 10 positions. Add a fourth tab with data-mode="celtic-cross", call roxy.tarot.castCelticCross({ body: {} }), set spread.spread = 'celtic-cross', then assign spread.data. <roxy-tarot-spread> renders all 10 positions with no extra code.
Ready-made template
tarot-starter-app is the full mobile build: React Native + Expo + TypeScript, full 78-card Rider-Waite deck, Celtic Cross spreads, daily readings.
Seed the daily card per user. Pass {"seed": userId} in the body. Same user gets the same card all day. Perfect for push notifications and daily email cadence.
Move the key server-side. Browser-embedded secret keys are for prototyping only. Use a publishable key (pk_live_*, origin-restricted) or proxy.
Cache the card catalog. Call GET /tarot/cards once, store it. Users browse the full 78-card deck without hitting the API per view.
Deploy to Cloudflare Pages or Vercel. Free tier covers thousands of visitors a month.
Gotchas
Each mode names its reading field differently. Daily card returns dailyMessage, yes-no returns answer plus interpretation, three-card returns summary at the top plus per-position interpretation. The components read the right field per shape, so you only pass the unwrapped response.
Reversed cards set card.reversed: true. The components flip the image and label it automatically. The meaning text is already context-aware.
Seeded is deterministic per day. Pass seed: userId and the same user gets the same daily card for the whole calendar date. Resets at UTC midnight.
imageUrl points to the RoxyAPI CDN. No image hosting needed. The path is stable enough to cache client-side.
Three-card positions[] is always length 3, with name values Past, Present, Future. Celtic Cross returns length 10.
What to build next
The AI chatbot tutorial wires tarot tools to an LLM so users ask natural-language questions.
The dating app tutorial shows the astrology surface for cross-sell after a tarot reading.
R
RosieYour AI guide to RoxyAPI
R
Hi, I am Rosie, your guide to the RoxyAPI insight tools.
Ask me to read your birth chart, pull a card, or map your numbers, and I will interpret what it means for you. Unlike most AIs, I never make the numbers up: every reading runs on real, verified calculations. Curious about the API, pricing, or docs instead? Ask me that too.