Tarot Data Model for Software: Cards, Spreads, Readings
How to design a tarot data model for applications. Covers card schemas, spread definitions, reading objects, database tables, and working API examples.
TL;DR
- A tarot deck is a structured dataset of 78 cards: 22 Major Arcana and 56 Minor Arcana across 4 suits, each with upright and reversed interpretations.
- Spreads are schemas that define named positions with interpretive contexts, transforming the same card into different meanings depending on placement.
- A reading is a composite object combining a spread definition, drawn cards placed in positions, reversal states, and generated interpretations.
- Build a complete tarot reading feature with the Roxy Tarot API in under 30 minutes.
About the author: Valentina Alcantara is a tarot reader and crystal healing practitioner with 15 years of experience across Mexico, Argentina, and Spain. She founded TarotVivo, an online school through which she has certified over 3,000 tarot readers across Latin America. Her interpretations draw on Rider-Waite symbolism, Mesoamerican cosmology, and the healing properties of crystals native to the Americas.
If you are building a tarot application, you need a solid tarot data model before writing a single line of UI code. Most tarot apps treat cards as flat lists and readings as random outputs. The result is brittle code that cannot support spreads, reversals, or position-dependent interpretation. This guide covers how to model the tarot deck as a typed data structure, define spreads as reusable schemas, compose readings as first-class objects, and design database tables that support all three. Every example maps directly to real API responses you can query today.
The tarot data model starts with 78 typed cards
A standard Rider-Waite tarot deck contains exactly 78 cards divided into two groups. The Major Arcana consists of 22 numbered trump cards (0 through 21), running from The Fool to The World. These represent major life themes, spiritual lessons, and karmic turning points. The Minor Arcana consists of 56 cards across four suits: Cups (emotions and relationships), Wands (creativity and passion), Swords (intellect and conflict), and Pentacles (material wealth and finances). Each suit contains 14 cards: Ace through 10, then Page, Knight, Queen, and King.
Every card in your data model needs these fields at minimum: a unique identifier, a display name, an arcana type (major or minor), an optional suit (only for minor arcana), a number, and an image URL. For the list endpoint, this lightweight schema keeps payloads small when browsing the full deck. Here is what a card looks like from the Roxy Tarot API:
curl -s "https://roxyapi.com/api/v2/tarot/cards?arcana=major&limit=3" \
-H "X-API-Key: YOUR_API_KEY"
{
"total": 22,
"limit": 3,
"offset": 0,
"cards": [
{
"id": "fool",
"name": "The Fool",
"arcana": "major",
"suit": null,
"number": 0,
"imageUrl": "https://roxyapi.com/img/tarot/major/fool.jpg"
}
]
}
Ready to build this? Roxy Tarot API gives you the complete 78-card Rider-Waite deck with full upright and reversed interpretations, spreads, and daily readings. See pricing.
How reversed cards double the interpretation space
The detail endpoint for a single card reveals the full depth of your data model. Each card carries two complete sets of meanings: upright and reversed. When a card is drawn upside down during a reading, its energy shifts. The Fool upright means new beginnings and spontaneity. The Fool reversed means recklessness and poor judgment. This reversal mechanic means your system must handle 78 cards multiplied by 2 orientations, giving you 156 distinct interpretive states.
Each orientation contains keywords for quick reference, a full narrative description, and domain-specific guidance across love, career, finances, health, and spirituality. Fetch the complete card detail like this:
curl -s "https://roxyapi.com/api/v2/tarot/cards/fool" \
-H "X-API-Key: YOUR_API_KEY"
The response includes top-level keywords with both upright and reversed arrays, plus full upright and reversed objects containing keywords, description, love, career, finances, health, and spirituality fields. Storing these as nested objects rather than flat columns makes your schema extensible. When you add a new interpretation domain later, you add a field to the meaning object instead of altering your table structure.
Spreads as reusable schemas with named positions
A spread is not just a number of cards. It is a schema that defines positions, each with a name and an interpretive context. The three-card spread has three positions: Past, Present, and Future. The Celtic Cross has ten positions: Present Situation, Challenge, Distant Past, Recent Past, Best Outcome, Near Future, Your Approach, External Influences, Hopes and Fears, and Final Outcome. Each position modifies how the drawn card is interpreted. The Tower in the "Past" position means a disruption that already happened. The Tower in the "Near Future" position means a disruption that is approaching.
This position-dependent interpretation is the key insight for your data model. A spread definition is an array of position objects, each with a name and an interpretation field that describes what that slot reveals. The API handles card drawing and position-specific interpretation for you:
curl -s -X POST "https://roxyapi.com/api/v2/tarot/spreads/three-card" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question": "What do I need to know about my career?"}'
The response returns a positions array where each element contains a position number, a name, a position-specific interpretation, and a card object with id, name, arcana, reversed boolean, keywords, meaning, and imageUrl.
The reading as a composite object
A reading brings together the spread schema and the drawn cards into a single composite structure. In data modeling terms, a reading is a join between a spread definition and a set of card draws placed into named positions. The response shape from the Celtic Cross endpoint illustrates this:
curl -s -X POST "https://roxyapi.com/api/v2/tarot/spreads/celtic-cross" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question": "What should I know about this situation?", "seed": "demo-2026"}'
The response includes spread (the spread name), question, seed, a positions array of 10 elements, and a summary that weaves all cards into a cohesive narrative. The seed parameter is critical for developers. Passing the same seed produces the same card draws in the same positions every time. This makes readings reproducible, which matters for testing, debugging, sharing saved readings, and ensuring consistent results when a user revisits the same reading. Omit the seed for truly random draws.
Building custom spreads with the schema builder
The custom spread endpoint lets you define your own position schemas at request time. You send an array of position definitions and the API draws one card per position, returning the same structured response. This is where the tarot data model becomes fully programmable:
curl -s -X POST "https://roxyapi.com/api/v2/tarot/spreads/custom" \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"spreadName": "Chakra Reading",
"positions": [
{"name": "Root", "interpretation": "Your foundation and security"},
{"name": "Sacral", "interpretation": "Your creativity and emotions"},
{"name": "Solar Plexus", "interpretation": "Your confidence and willpower"},
{"name": "Heart", "interpretation": "Your capacity for love and compassion"},
{"name": "Throat", "interpretation": "Your communication and truth"},
{"name": "Third Eye", "interpretation": "Your intuition and insight"},
{"name": "Crown", "interpretation": "Your spiritual connection"}
],
"question": "What does each energy center need right now?",
"seed": "chakra-demo"
}'
You can define 1 to 10 positions. Each position requires a name and an interpretation. The spreadName field labels the response. This endpoint powers therapists building signature spreads, coaches creating workshop tools, and app developers offering customizable reading experiences. The position schema you send becomes the scaffold for the reading response. No two custom spreads need to look alike.
Database schema considerations for tarot apps
When persisting tarot data in your own database, three tables cover the full domain. The cards table holds static reference data: the 78 cards with their IDs, names, arcana types, suits, numbers, and image URLs. This table is seeded once and rarely updated. You can enrich it with keyword and meaning columns, or fetch interpretations from the API on demand and cache them.
The spreads table stores spread definitions with a name, description, and a JSON column for position metadata (an array of {name, interpretation} objects). Predefined spreads like three-card and Celtic Cross are seeded rows. Custom spreads created by users become new rows, linking to the user who created them.
The readings table records completed readings. Each row references a spread ID, stores the drawn cards and their positions as a JSON column (mirroring the API positions array structure), captures the seed if one was used, the question text, the summary narrative, and a timestamp. This table grows with every reading your users perform. Index on user ID and timestamp for efficient history queries. The JSON positions column preserves the complete card-in-position mapping without needing a separate junction table.
Frequently Asked Questions
Q: How many cards are in a standard tarot deck? A: A standard Rider-Waite tarot deck contains 78 cards. The Major Arcana has 22 cards numbered 0 through 21, representing major life themes. The Minor Arcana has 56 cards across four suits (Cups, Wands, Swords, Pentacles) with 14 cards each.
Q: What is a tarot spread and how does it affect interpretation? A: A tarot spread is a predefined layout of positions, each with a name and interpretive context. The same card means different things in different positions. The Tower in a "Past" position means disruption already experienced, while in a "Future" position it signals approaching change.
Q: How do you make tarot readings reproducible in software? A: Pass a seed value when requesting a reading. The same seed combined with the same spread produces identical card draws and positions every time. This enables testing, debugging, sharing saved readings, and consistent user experiences across sessions.
Q: Can I create custom tarot spreads through an API? A: Yes. The Roxy Tarot API custom spread endpoint accepts 1 to 10 position definitions, each with a name and interpretation context. The API draws cards for your defined positions and returns structured results matching your schema.
Q: What is the difference between upright and reversed tarot cards in data terms?
A: Each card has two complete interpretation sets. Upright represents the standard energy of the card. Reversed represents blocked, inverted, or internalized energy. Your data model must track a boolean reversed field per drawn card and serve the correct meaning set based on orientation.
Start modeling tarot data with a production API
Designing a tarot data model means thinking in three layers: cards as reference data, spreads as position schemas, and readings as composite objects that join the two. The reversal mechanic doubles your interpretation space. Seeded randomness makes readings testable and shareable. Position-dependent meaning transforms static card data into contextual guidance.
The Roxy Tarot API gives you all 78 cards, multiple predefined spreads, a custom spread builder, and structured JSON responses that map directly to the tarot data model described in this guide. Browse the full API reference or check pricing to start building.