The problem
A client wanted daily horoscopes on their wellness app. All 12 signs, refreshed daily, English first with Hindi coming in phase two. The deadline was end of week. I did not want to spend three days reading documentation for an API I had never used.
Here is the stack I ended up with, and the working Python you can drop into a project today.
What I used
DivineAPI for the horoscope endpoint
Python 3.11
The requests library (pip install requests)
About 10 minutes of actual work
Step 1: Get your API key
Sign up at divineapi.com, 14-day free trial, you will need a credit card to register. Once you are in the dashboard, grab your API key. Two things they hand you that you will need:
The api_key value (goes in the request body)
An Authorization token (goes in the header as Bearer {token})
Yes, two separate auth bits. I did not catch this on first read and spent ten minutes wondering why I was getting 401s. More on that below.
Step 2: Your first call
Here is the smallest working request for the daily horoscope endpoint:
import requests
url = "https://astroapi-5.divineapi.com/api/v5/daily-horoscope"
headers = {
"Authorization": "Bearer YOUR_AUTH_TOKEN"
}
payload = {
"api_key": "YOUR_API_KEY",
"sign": "leo",
"h_day": "today", # also accepts "yesterday" or "tomorrow"
"tzone": 5.5 # IST. timezone offset as a float, not a string
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
the prediction is split into 5 life areas + a "luck" array
print(data["data"]["prediction"]["personal"])
That is it. One POST, one JSON response, daily horoscope for Leo.
A few non-obvious bits the docs are right about but easy to miss:
The endpoint is on astroapi-5.divineapi.com, not the apex divineapi.com. They run different astro services on numbered subdomains.
The day parameter is named h_day, not day. I assumed day and got a 422.
tzone is a Float, 5.5 for IST. Not a string. Not "Asia/Kolkata". Not 5. I learned this the hard way (see "the part where I got stuck").
For non-English you swap the host to astroapi-5-translator.divineapi.com and add a lan field. They support 25 languages including Indonesian and Greek (the language list got expanded in April 2026).
What comes back
Here is the actual response shape, trimmed for readability:
{
"success": 1,
"data": {
"sign": "Leo",
"date": "2026-04-23",
"prediction": {
"personal": "Your personal life is full of vibrant energy today...",
"health": "Pay attention to physical wellness today, Leo...",
"profession": "Today, you may find yourself inspired at work, Leo...",
"emotions": "Emotionally, you may feel heightened sensitivity, Leo...",
"travel": "Adventure calls today, Leo! Whether it's a spontaneous day trip...",
"luck": [
"Colors of the day : Gold, Orange",
"Lucky Numbers of the day : 4, 9, 13",
"Lucky Alphabets you will be in sync with : L, S",
"Cosmic Tip : Beware of impulsive actions; stay grounded and focused.",
"Tips for Singles : Express your interests confidently...",
"Tips for Couples : Share your dreams; strengthen your bond..."
]
},
"special": {
"lucky_color_codes": ["#FFD700", "#FFA500"],
"horoscope_percentage": {
"personal": 85, "health": 75, "profession": 80, "emotions": 78
}
}
}
}
Two things worth noticing. The prediction is broken into five life areas (personal, health, profession, emotions, travel) plus a luck array of one-liners. So you can render the full daily horoscope, or just the personal text, or just the lucky numbers as a widget. Useful flexibility. Second, special.lucky_color_codes gives you actual hex codes, which means you can theme the daily card with the lucky colour without writing a sign-to-colour map yourself.
Average response times in my testing came back around 74ms over a few hundred requests, which tracks with their published "from 72ms" claim. Fast enough that you do not need a loading state for a single sign.
Step 3: All 12 signs in one loop
For a daily-refresh job that fills a database or warms a cache, you want every sign in one go. Wrap the call in a function and loop:
import requests
URL = "https://astroapi-5.divineapi.com/api/v5/daily-horoscope"
HEADERS = {"Authorization": "Bearer YOUR_AUTH_TOKEN"}
API_KEY = "YOUR_API_KEY"
SIGNS = [
"aries", "taurus", "gemini", "cancer", "leo", "virgo",
"libra", "scorpio", "sagittarius", "capricorn", "aquarius", "pisces"
]
def fetch_daily(sign):
payload = {
"api_key": API_KEY,
"sign": sign,
"h_day": "today",
"tzone": 5.5
}
r = requests.post(URL, headers=HEADERS, json=payload, timeout=10)
r.raise_for_status()
return r.json()["data"]
results = {sign: fetch_daily(sign) for sign in SIGNS}
now results["leo"]["prediction"]["personal"] etc.
print(f"Fetched {len(results)} sign predictions")
Twelve calls, completes in under a second on a decent connection. If you are serving these to users live, cache the response per-sign per-day. The data only changes once every 24 hours. There is no good reason to hit the API on every page load.
Step 4: Add weekly and monthly horoscopes
Same auth, same response shape, different endpoint and one parameter name change:
WEEKLY_URL = "https://astroapi-5.divineapi.com/api/v5/weekly-horoscope"
MONTHLY_URL = "https://astroapi-5.divineapi.com/api/v5/monthly-horoscope"
def fetch_weekly(sign):
payload = {
"api_key": API_KEY,
"sign": sign,
"week": "current", # also "prev" or "next"
"tzone": 5.5
}
r = requests.post(WEEKLY_URL, headers=HEADERS, json=payload, timeout=10)
return r.json()["data"]
def fetch_monthly(sign):
payload = {
"api_key": API_KEY,
"sign": sign,
"month": "current", # also "prev" or "next"
"tzone": 5.5
}
r = requests.post(MONTHLY_URL, headers=HEADERS, json=payload, timeout=10)
return r.json()["data"]
Worth knowing: DivineAPI ships 6 horoscope endpoints total under the Horoscope and Tarot category. Daily, Weekly, Monthly, Yearly, Chinese Horoscope, and Numerology Horoscope. So if you ever want to add yearly forecasts or Chinese zodiac alongside the Western ones, the same API key covers all of them.
The part where I got stuck
Two stupid bugs cost me about 25 minutes total. Both worth flagging because they will cost you time too if nobody warns you.
Bug 1: "day" vs "h_day". I assumed the parameter would be called day because that is what I would call it. The actual name is h_day. The API responded with a 422 and a perfectly clear error message saying the field was missing. I looked at my code, saw day, and somehow my brain kept reading it as h_day. Three minutes of "but it IS there, what is wrong with this thing". Lesson: when an API says a field is missing and you swear it is there, check the name character by character.
Bug 2: timezone as a string. I sent "tzone": "5.5" because I was building the payload from form input and forgot to cast. The API accepted it, returned a 200, and gave me back a horoscope. Looked fine. Except the date in the response was off by one for a chunk of users, depending on what time of day they hit the endpoint. Took a while to pin down. The API expects tzone as a Float. Send a string and it silently degrades the date calculation. Cast your inputs.
If you are integrating this into a Django or Flask form, do the cast at the serializer layer and write a test for it.
What I'd do differently
Three things, in order of how much pain they would have saved.
Cache aggressively. I should have set up a Redis cache from the start. The horoscope data is per-sign per-day. Twelve API calls per day total, the rest served from cache. Saves the API budget and removes the latency entirely.
Centralise the auth headers. I scattered HEADERS = {...} across three files before I refactored. A small wrapper function or a requests.Session would have been better from day one.
Don't roll your own retry logic. Use tenacity or requests-retry-session for the 5xx case. I wrote a half-baked retry loop, immediately regretted it, and ripped it out for the library.
Wrapping up
That is a working horoscope feature in about 10 minutes of code. You can extend it to weekly, monthly, yearly, Chinese, or numerology horoscopes with the same API key. They have a Postman collection at the docs website which is genuinely useful for poking at the response before you write any code. Full docs at developers.divineapi.com.
DivineAPI has a 14-day free trial if you want to try this yourself. If you ship something with it, drop a comment. Always curious what people end up building.
Top comments (0)