Tarot API Integration Guide: Add Card Readings to Your iOS/Android App
Complete technical guide for integrating tarot readings into mobile apps. Learn API authentication, endpoint structure, response handling, error management, and real-world code examples for iOS and Android.
Tarot API Integration Guide: Add Card Readings to Your iOS/Android App
Want to add mystical tarot reading features to your mobile app without dealing with card databases, interpretation logic, or complex algorithms? The RoxyAPI Tarot API provides everything you need: 78 professionally illustrated cards, detailed upright and reversed meanings, multiple spread types (Celtic Cross, three-card, love, career), and even reproducible seeded readings for consistent experiences.
This technical guide walks through complete API integration for both iOS and Android platforms. You'll learn authentication patterns, endpoint structures, response handling, error management, and production-ready code patterns that you can ship today.
What You'll Build
By the end of this guide, you'll integrate:
- Card Database Access: Query all 78 cards with filtering by arcana, suit, and number
- Daily Readings: Reproducible daily cards based on date and user ID
- Custom Spreads: Three-card readings, Celtic Cross (10 cards), love spreads, career spreads
- Yes/No Answers: Quick oracle-style guidance for binary questions
- Seeded Draws: Deterministic card selection for sharing or testing
All endpoints return clean JSON with card metadata, keywords, interpretations, and high-quality image URLs.
Prerequisites
iOS Requirements:
- Xcode 14+ with Swift 5.7+
- iOS 15.0+ deployment target
- URLSession or Alamofire for networking
Android Requirements:
- Android Studio Hedgehog+ with Kotlin 1.9+
- minSdk 24 (Android 7.0) or higher
- Retrofit or OkHttp for API calls
API Access:
- Visit RoxyAPI Pricing
- Choose a plan
- Complete checkout - your API key displays immediately (save it!)
- Test your key:
curl -H "X-API-Key: YOUR_KEY" https://roxyapi.com/api/v2/tarot/cards
API Fundamentals
Authentication Pattern
All requests require an X-API-Key header. The API uses HMAC-signed keys (not JWTs) for blazing-fast verification:
curl -H "X-API-Key: sub_abc123.signature456" \
https://roxyapi.com/api/v2/tarot/cards
Never hardcode keys in your app code. Use:
- iOS: Xcode configuration files or Keychain
- Android:
BuildConfigfields fromgradle.propertiesor Android Keystore
Base URL
https://roxyapi.com/api
All tarot endpoints start with /tarot prefix.
Rate Limits
Rate limits are monthly only (no per-second throttling):
- X-RateLimit-Limit: Total requests per month from your plan
- X-RateLimit-Used: Requests consumed this month
- X-RateLimit-Remaining: Requests left this month
Check response headers to display usage to users:
iOS Example:
if let limit = response.value(forHTTPHeaderField: "X-RateLimit-Limit"),
let used = response.value(forHTTPHeaderField: "X-RateLimit-Used") {
print("API Usage: \(used)/\(limit) requests this month")
}
Android Example:
val limit = response.headers()["X-RateLimit-Limit"]
val used = response.headers()["X-RateLimit-Used"]
println("API Usage: $used/$limit requests this month")
Response Format
All successful responses return data directly (no { success: true, data: {...} } wrapper):
{
"id": "fool",
"name": "The Fool",
"arcana": "major",
"number": 0,
"keywords": ["Beginnings", "innocence", "spontaneity"],
"imageUrl": "https://roxyapi.com/img/tarot/major/fool.jpg"
}
Errors return clean error objects with appropriate HTTP status codes:
{
"error": "Invalid API key"
}
Core Endpoints
1. List All Cards
Get the complete 78-card tarot deck with optional filtering:
Endpoint:
GET /tarot/cards
Query Parameters:
arcana(optional): Filter bymajororminorsuit(optional): Filter minor arcana bycups,wands,swords,pentaclesnumber(optional): Filter by card number (1-14 for minor, where Ace=1, Page=11, Knight=12, Queen=13, King=14)
iOS Implementation:
struct TarotCard: Codable {
let id: String
let name: String
let arcana: String
let suit: String?
let number: Int?
let imageUrl: String
}
class TarotAPIService {
private let baseURL = "https://roxyapi.com/api"
private let apiKey: String
init(apiKey: String) {
self.apiKey = apiKey
}
func fetchCards(
arcana: String? = nil,
suit: String? = nil,
number: Int? = nil
) async throws -> [TarotCard] {
var components = URLComponents(string: "\(baseURL)/tarot/cards")!
var queryItems: [URLQueryItem] = []
if let arcana = arcana {
queryItems.append(URLQueryItem(name: "arcana", value: arcana))
}
if let suit = suit {
queryItems.append(URLQueryItem(name: "suit", value: suit))
}
if let number = number {
queryItems.append(URLQueryItem(name: "number", value: "\(number)"))
}
if !queryItems.isEmpty {
components.queryItems = queryItems
}
var request = URLRequest(url: components.url!)
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw TarotAPIError.invalidResponse
}
return try JSONDecoder().decode([TarotCard].self, from: data)
}
}
// Usage
let service = TarotAPIService(apiKey: "YOUR_API_KEY")
let majorArcana = try await service.fetchCards(arcana: "major")
let cupsCards = try await service.fetchCards(suit: "cups")
Android Implementation:
data class TarotCard(
val id: String,
val name: String,
val arcana: String,
val suit: String?,
val number: Int?,
val imageUrl: String
)
interface TarotAPI {
@GET("/api/tarot/cards")
suspend fun getCards(
@Query("arcana") arcana: String? = null,
@Query("suit") suit: String? = null,
@Query("number") number: Int? = null,
@Header("X-API-Key") apiKey: String
): List<TarotCard>
}
class TarotRepository(private val apiKey: String) {
private val api: TarotAPI = Retrofit.Builder()
.baseUrl("https://roxyapi.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(TarotAPI::class.java)
suspend fun fetchCards(
arcana: String? = null,
suit: String? = null,
number: Int? = null
): Result<List<TarotCard>> = try {
val cards = api.getCards(arcana, suit, number, apiKey)
Result.success(cards)
} catch (e: Exception) {
Result.failure(e)
}
}
// Usage in ViewModel
class TarotViewModel : ViewModel() {
private val repository = TarotRepository(BuildConfig.TAROT_API_KEY)
fun loadMajorArcana() {
viewModelScope.launch {
repository.fetchCards(arcana = "major")
.onSuccess { cards -> _cards.value = cards }
.onFailure { error -> _error.value = error.message }
}
}
}
2. Get Single Card Details
Retrieve detailed information for a specific card including upright/reversed keywords and full interpretations:
Endpoint:
GET /tarot/cards/{id}
Path Parameters:
id: Card identifier in kebab-case (e.g.,fool,ace-of-cups,queen-of-swords)
Response Example:
{
"id": "fool",
"name": "The Fool",
"arcana": "major",
"number": 0,
"keywords": {
"upright": ["Beginnings", "innocence", "spontaneity", "free spirit"],
"reversed": ["Holding back", "recklessness", "risk-taking"]
},
"upright": "The Fool is a card of new beginnings, opportunity and potential...",
"reversed": "When The Fool appears reversed, you may be holding back...",
"imageUrl": "https://roxyapi.com/img/tarot/major/fool.jpg"
}
iOS Implementation:
struct CardDetail: Codable {
let id: String
let name: String
let arcana: String
let number: Int?
let suit: String?
let keywords: Keywords
let upright: String
let reversed: String
let imageUrl: String
struct Keywords: Codable {
let upright: [String]
let reversed: [String]
}
}
extension TarotAPIService {
func fetchCardDetail(id: String) async throws -> CardDetail {
let url = URL(string: "\(baseURL)/tarot/cards/\(id)")!
var request = URLRequest(url: url)
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw TarotAPIError.invalidResponse
}
return try JSONDecoder().decode(CardDetail.self, from: data)
}
}
Android Implementation:
data class CardDetail(
val id: String,
val name: String,
val arcana: String,
val number: Int?,
val suit: String?,
val keywords: Keywords,
val upright: String,
val reversed: String,
val imageUrl: String
) {
data class Keywords(
val upright: List<String>,
val reversed: List<String>
)
}
interface TarotAPI {
// ... previous methods
@GET("/api/tarot/cards/{id}")
suspend fun getCardDetail(
@Path("id") id: String,
@Header("X-API-Key") apiKey: String
): CardDetail
}
3. Draw Random Cards
Draw one or more random cards with control over reversals and duplicates:
Endpoint:
POST /tarot/draw
Request Body:
{
"count": 3,
"allowReversals": true,
"allowDuplicates": false,
"seed": "optional-seed-for-reproducibility"
}
Parameters:
count(required): Number of cards (1-78)allowReversals(optional): Allow reversed cards, defaulttrueallowDuplicates(optional): Allow same card multiple times, defaultfalseseed(optional): String seed for reproducible draws
Response:
{
"cards": [
{
"id": "tower",
"name": "The Tower",
"arcana": "major",
"number": 16,
"position": 1,
"reversed": false,
"keywords": ["Sudden change", "upheaval", "chaos"],
"meaning": "When The Tower appears...",
"imageUrl": "https://roxyapi.com/img/tarot/major/tower.jpg"
}
],
"count": 1,
"seed": "optional-seed-for-reproducibility"
}
iOS Implementation:
struct DrawRequest: Codable {
let count: Int
let allowReversals: Bool
let allowDuplicates: Bool
let seed: String?
}
struct DrawnCard: Codable {
let id: String
let name: String
let arcana: String
let suit: String?
let number: Int?
let position: Int
let reversed: Bool
let keywords: [String]
let meaning: String
let imageUrl: String
}
struct DrawResponse: Codable {
let cards: [DrawnCard]
let count: Int
let seed: String?
}
extension TarotAPIService {
func drawCards(
count: Int,
allowReversals: Bool = true,
allowDuplicates: Bool = false,
seed: String? = nil
) async throws -> DrawResponse {
let url = URL(string: "\(baseURL)/tarot/draw")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = DrawRequest(
count: count,
allowReversals: allowReversals,
allowDuplicates: allowDuplicates,
seed: seed
)
request.httpBody = try JSONEncoder().encode(body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw TarotAPIError.invalidResponse
}
return try JSONDecoder().decode(DrawResponse.self, from: data)
}
}
Android Implementation:
data class DrawRequest(
val count: Int,
val allowReversals: Boolean = true,
val allowDuplicates: Boolean = false,
val seed: String? = null
)
data class DrawnCard(
val id: String,
val name: String,
val arcana: String,
val suit: String?,
val number: Int?,
val position: Int,
val reversed: Boolean,
val keywords: List<String>,
val meaning: String,
val imageUrl: String
)
data class DrawResponse(
val cards: List<DrawnCard>,
val count: Int,
val seed: String?
)
interface TarotAPI {
// ... previous methods
@POST("/api/tarot/draw")
suspend fun drawCards(
@Body request: DrawRequest,
@Header("X-API-Key") apiKey: String
): DrawResponse
}
4. Celtic Cross Spread
The most comprehensive 10-card spread revealing past influences, present situation, future possibilities, and final outcome:
Endpoint:
POST /tarot/spreads/celtic-cross
Request Body:
{
"question": "What opportunities await me in my career?",
"seed": "optional-seed"
}
Response Structure:
{
"spread": "Celtic Cross",
"question": "What opportunities await me in my career?",
"seed": "optional-seed",
"positions": [
{
"position": 1,
"name": "Present Situation",
"interpretation": "Represents what is happening at present...",
"card": {
"id": "nine-of-cups",
"name": "Nine of Cups",
"position": 1,
"reversed": false,
"keywords": ["Contentment", "satisfaction", "gratitude"],
"meaning": "You know those moments when...",
"imageUrl": "..."
}
}
]
}
Position Meanings:
- Present Situation - Current state and how you perceive it
- Challenge - Immediate obstacle requiring attention
- Distant Past - Events that led to present situation
- Near Future - What's likely within weeks/months
- Above - Your goal, aspiration, conscious mind
- Below - Subconscious realm, underlying feelings
- Advice - Guidance on how to proceed
- External Influences - Factors beyond your control
- Hopes and Fears - Intertwined desires and anxieties
- Final Outcome - Where situation is headed
iOS Implementation:
struct CelticCrossRequest: Codable {
let question: String?
let seed: String?
}
struct SpreadPosition: Codable {
let position: Int
let name: String
let interpretation: String
let card: DrawnCard
}
struct CelticCrossResponse: Codable {
let spread: String
let question: String?
let seed: String?
let positions: [SpreadPosition]
let summary: String
}
extension TarotAPIService {
func celticCross(question: String? = nil, seed: String? = nil) async throws -> CelticCrossResponse {
let url = URL(string: "\(baseURL)/tarot/spreads/celtic-cross")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = CelticCrossRequest(question: question, seed: seed)
request.httpBody = try JSONEncoder().encode(body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw TarotAPIError.invalidResponse
}
return try JSONDecoder().decode(CelticCrossResponse.self, from: data)
}
}
5. Daily Tarot Reading
Get a deterministic daily card based on date and optional user ID:
Endpoint:
POST /tarot/daily
Request Body:
{
"date": "2025-12-27",
"userId": "user123"
}
Parameters:
date(optional): ISO date string (YYYY-MM-DD), defaults to today UTCuserId(optional): User identifier for personalized daily cards (same user + date = same card)
Response:
{
"date": "2025-12-27",
"userId": "user123",
"card": {
"id": "star",
"name": "The Star",
"reversed": false,
"keywords": ["Hope", "faith", "purpose", "renewal"],
"meaning": "The Star brings renewed hope...",
"imageUrl": "..."
},
"message": "Your daily guidance for December 27, 2025"
}
iOS Implementation:
struct DailyRequest: Codable {
let date: String?
let userId: String?
}
struct DailyResponse: Codable {
let date: String
let seed: String
let card: DrawnCard
let dailyMessage: String
}
extension TarotAPIService {
func dailyReading(date: String? = nil, userId: String? = nil) async throws -> DailyResponse {
let url = URL(string: "\(baseURL)/tarot/daily")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let body = DailyRequest(date: date, userId: userId)
request.httpBody = try JSONEncoder().encode(body)
let (data, response) = try await URLSession.shared.data(for: request)
guard let httpResponse = response as? HTTPURLResponse,
(200...299).contains(httpResponse.statusCode) else {
throw TarotAPIError.invalidResponse
}
return try JSONDecoder().decode(DailyResponse.self, from: data)
}
}
6. Yes/No Reading
Quick oracle-style guidance for binary questions:
Endpoint:
POST /tarot/yes-no
Request Body:
{
"question": "Should I accept the job offer?",
"seed": "optional-seed"
}
Response:
{
"question": "Should I accept the job offer?",
"answer": "yes",
"confidence": "strong",
"card": {
"id": "sun",
"name": "The Sun",
"reversed": false,
"keywords": ["Success", "radiance", "abundance"],
"meaning": "...",
"imageUrl": "..."
},
"interpretation": "The Sun shines brightly on this question..."
}
Answer Types:
yes- Strong positive indicationno- Clear negative indicationmaybe- Unclear, requires more reflection
Confidence Levels:
strong- Major arcana upright or highly positive cardmoderate- Minor arcana or neutral cardweak- Reversed card or ambiguous meaning
Error Handling
HTTP Status Codes
200- Success400- Bad request (invalid parameters, malformed JSON)401- Unauthorized (missing or invalid API key)429- Rate limit exceeded (monthly quota exhausted)500- Server error (contact support if persistent)
Error Response Format
{
"error": "Human-readable error message"
}
iOS Error Handling Pattern
enum TarotAPIError: Error {
case invalidResponse
case unauthorized
case rateLimitExceeded
case serverError
case decodingError
case networkError(Error)
case unknown(String)
}
extension TarotAPIService {
private func handleResponse(_ response: HTTPURLResponse, data: Data) throws {
switch response.statusCode {
case 200...299:
return
case 401:
throw TarotAPIError.unauthorized
case 429:
throw TarotAPIError.rateLimitExceeded
case 500...599:
throw TarotAPIError.serverError
default:
if let errorResponse = try? JSONDecoder().decode(ErrorResponse.self, from: data) {
throw TarotAPIError.unknown(errorResponse.error)
}
throw TarotAPIError.invalidResponse
}
}
}
struct ErrorResponse: Codable {
let error: String
}
// Usage in ViewModel
func loadDailyCard() {
Task {
do {
let daily = try await service.dailyReading()
self.dailyCard = daily.card
} catch TarotAPIError.unauthorized {
self.error = "Invalid API key. Please check your subscription."
} catch TarotAPIError.rateLimitExceeded {
self.error = "Monthly limit reached. Upgrade your plan."
} catch {
self.error = "Failed to load daily card. Try again."
}
}
}
Android Error Handling Pattern
sealed class TarotResult<out T> {
data class Success<T>(val data: T) : TarotResult<T>()
sealed class Error : TarotResult<Nothing>() {
data class Network(val exception: Exception) : Error()
data object Unauthorized : Error()
data object RateLimitExceeded : Error()
data class Server(val message: String) : Error()
}
}
class TarotRepository(private val apiKey: String) {
suspend fun fetchDailyReading(
date: String? = null,
userId: String? = null
): TarotResult<DailyResponse> = try {
val response = api.getDailyReading(
DailyRequest(date, userId),
apiKey
)
TarotResult.Success(response)
} catch (e: HttpException) {
when (e.code()) {
401 -> TarotResult.Error.Unauthorized
429 -> TarotResult.Error.RateLimitExceeded
in 500..599 -> TarotResult.Error.Server(e.message ?: "Server error")
else -> TarotResult.Error.Network(e)
}
} catch (e: Exception) {
TarotResult.Error.Network(e)
}
}
// Usage in ViewModel
fun loadDailyCard() {
viewModelScope.launch {
when (val result = repository.fetchDailyReading()) {
is TarotResult.Success -> _dailyCard.value = result.data.card
is TarotResult.Error.Unauthorized -> _error.value = "Invalid API key"
is TarotResult.Error.RateLimitExceeded -> _error.value = "Monthly limit reached"
is TarotResult.Error.Server -> _error.value = "Server error"
is TarotResult.Error.Network -> _error.value = "Network error"
}
}
}
Production Best Practices
1. Image Caching
All card images are served from CDN (https://roxyapi.com/img/tarot/). Implement aggressive caching:
iOS (Kingfisher):
import Kingfisher
ImageView.kf.setImage(
with: URL(string: card.imageUrl),
options: [
.transition(.fade(0.2)),
.cacheMemoryOnly(false),
.diskCacheExpiration(.days(30))
]
)
Android (Coil):
ImageView.load(card.imageUrl) {
crossfade(true)
memoryCachePolicy(CachePolicy.ENABLED)
diskCachePolicy(CachePolicy.ENABLED)
}
2. Offline Support
Cache API responses locally for offline access:
iOS (SwiftData):
@Model
class CachedCard {
@Attribute(.unique) var id: String
var name: String
var data: Data // JSON serialized
var cachedAt: Date
init(id: String, name: String, data: Data) {
self.id = id
self.name = name
self.data = data
self.cachedAt = Date()
}
}
Android (Room):
@Entity(tableName = "cached_cards")
data class CachedCard(
@PrimaryKey val id: String,
val name: String,
val jsonData: String,
val cachedAt: Long
)
@Dao
interface CardDao {
@Query("SELECT * FROM cached_cards WHERE id = :id")
suspend fun getCard(id: String): CachedCard?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertCard(card: CachedCard)
}
3. Request Retries
Implement exponential backoff for transient failures:
iOS:
func fetchWithRetry<T>(
maxAttempts: Int = 3,
operation: @escaping () async throws -> T
) async throws -> T {
var lastError: Error?
for attempt in 1...maxAttempts {
do {
return try await operation()
} catch {
lastError = error
if attempt < maxAttempts {
let delay = UInt64(pow(2.0, Double(attempt))) * NSEC_PER_SEC
try await Task.sleep(nanoseconds: delay)
}
}
}
throw lastError!
}
// Usage
let cards = try await fetchWithRetry {
try await service.fetchCards()
}
4. Usage Monitoring
Display API usage to users before they hit limits:
iOS SwiftUI:
struct UsageView: View {
@State private var limit: Int = 0
@State private var used: Int = 0
var body: some View {
VStack {
Text("API Usage")
.font(.headline)
ProgressView(value: Double(used), total: Double(limit))
Text("\(used) / \(limit) requests")
.font(.caption)
.foregroundColor(.secondary)
}
.task {
await loadUsage()
}
}
func loadUsage() async {
do {
let response = try await service.fetchCards(arcana: "major")
// Extract from response headers
} catch {
print("Failed to load usage")
}
}
}
Android Jetpack Compose:
@Composable
fun UsageCard(viewModel: TarotViewModel) {
val usage by viewModel.apiUsage.collectAsState()
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("API Usage", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
LinearProgressIndicator(
progress = usage.used.toFloat() / usage.limit.toFloat(),
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(4.dp))
Text(
"${usage.used} / ${usage.limit} requests",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
Testing Your Integration
1. Seed-Based Testing
Use consistent seeds for reproducible test data:
// Test suite
func testThreeCardSpread() async throws {
let response = try await service.drawCards(count: 3, seed: "test-seed-123")
XCTAssertEqual(response.cards.count, 3)
XCTAssertEqual(response.seed, "test-seed-123")
// Same seed always returns same cards
let response2 = try await service.drawCards(count: 3, seed: "test-seed-123")
XCTAssertEqual(response.cards[0].id, response2.cards[0].id)
}
2. Mock API Responses
Create mock responses for UI testing without consuming API quota:
protocol TarotAPIProtocol {
func fetchCards() async throws -> [TarotCard]
func drawCards(count: Int) async throws -> DrawResponse
}
class MockTarotService: TarotAPIProtocol {
func fetchCards() async throws -> [TarotCard] {
return [
TarotCard(id: "fool", name: "The Fool", arcana: "major", imageUrl: "...")
]
}
func drawCards(count: Int) async throws -> DrawResponse {
return DrawResponse(
cards: [DrawnCard(id: "fool", name: "The Fool", ...)],
count: count,
seed: nil
)
}
}
Next Steps
You now have a complete tarot reading integration! Here's what to build next:
- Daily Notifications: Push notifications with daily card at user's chosen time
- Reading History: Store user's past readings with notes and reflections
- Sharing: Generate beautiful card images for social media sharing
- Custom Spreads: Use
/tarot/drawendpoint to create your own spread layouts - Journaling: Combine readings with text input for personal growth tracking
Troubleshooting
Q: Getting 401 Unauthorized errors A: Verify your API key is correct and hasn't expired. Check your subscription status at roxyapi.com/products/tarot-api.
Q: Images not loading A: Ensure your app has internet permission and image URLs are being parsed correctly. All images are served over HTTPS from CDN.
Q: Rate limit exceeded too quickly A: Implement local caching for frequently accessed data (card list, individual card details). Only make API calls for dynamic content (daily cards, spreads).
Q: Inconsistent daily cards
A: Ensure you're passing consistent userId and date parameters. The API uses UTC timezone - convert user's local date to UTC.
Resources
- API Documentation: roxyapi.com/docs
- Pricing & Plans: roxyapi.com/pricing
- Support: Email [email protected] for integration help
- Example Apps: Check GitHub for open-source sample implementations
About RoxyAPI: Developer-focused API platform providing production-ready tarot, numerology, and astrology endpoints. Built for apps that need mystical features without the complexity of managing card databases, interpretation logic, or astronomical calculations. Pay per request with transparent monthly pricing.