✋ Palmistry API and 🎧 Audio Reports API are now live. Ship them in your app today.

Guides

Daily horoscope API: JSON for all 12 zodiac signs

A horoscope API returns written predictions for a zodiac sign. You send us a sign name, such as leo, and we return that sign's horoscope as JSON. Everyone born under the same sun sign sees the same text. (The sun sign is the sign the Sun was in on a person's birthday.)

This guide shows our daily, next-day, previous-day, weekly and monthly endpoints. Then it shows how to put all 12 signs on a website, how to cache them, and when to use a birth chart instead.

Every endpoint below is a POST to the base URL https://json.astrologyapi.com/v1 with a JSON body. Use an access token in the x-astrologyapi-key header, or HTTP Basic auth (user ID and API key) on a plan, as explained in Tokens vs API keys. We don't send CORS headers, so call the API from your server, not the browser.

What our horoscope API returns

Each endpoint takes the sign in the URL path and an optional timezone in the JSON body. The sign must be lowercase: aries, taurus, gemini, cancer, leo, virgo, libra, scorpio, sagittarius, capricorn, aquarius or pisces.

EndpointWhat we returnInputs
sun_sign_prediction/daily/:zodiacNameToday's horoscope in six fields: personal_life, profession, health, emotions, travel, luck.Sign, timezone (optional)
sun_sign_prediction/daily/next/:zodiacNameTomorrow's six fields, plus prediction_date.Sign, timezone (optional)
sun_sign_prediction/daily/previous/:zodiacNameYesterday's six fields, plus prediction_date.Sign, timezone (optional)
sun_sign_consolidated/daily/:zodiacNameToday's horoscope as one paragraph in prediction.Sign, timezone (optional)
horoscope_prediction/weekly/:zodiacNameweek_start_date and a prediction array of paragraphs.Sign, timezone (required)
horoscope_prediction/monthly/:zodiacNameprediction_month and a prediction array of paragraphs.Sign, timezone (optional)

These endpoints return English text. For the full field list of each one, see the horoscope API reference.

Your first call

Set ASTROLOGY_ACCESS_TOKEN as an environment variable. On a plan, you can set ASTROLOGY_USER_ID and ASTROLOGY_API_KEY instead. The Node and Python code below uses the token if it is set. Ask for today's Aries horoscope with curl:

curl -s -H "x-astrologyapi-key: $ASTROLOGY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"timezone":5.5}' \
  https://json.astrologyapi.com/v1/sun_sign_prediction/daily/aries

# With a user ID and API key (plan subscribers), replace the first line with:
# curl -s -u "$ASTROLOGY_USER_ID:$ASTROLOGY_API_KEY" \

The same call in Node.js:

// daily.mjs - Node 18+ (built-in fetch). Run it on your server.
// Uses your access token if set, otherwise your user ID and API key.
function authHeaders() {
  const token = process.env.ASTROLOGY_ACCESS_TOKEN
  if (token) return { 'x-astrologyapi-key': token }
  const userId = process.env.ASTROLOGY_USER_ID
  const apiKey = process.env.ASTROLOGY_API_KEY
  if (!userId || !apiKey) {
    throw new Error('Set ASTROLOGY_ACCESS_TOKEN, or ASTROLOGY_USER_ID and ASTROLOGY_API_KEY')
  }
  return {
    Authorization: 'Basic ' + Buffer.from(userId + ':' + apiKey).toString('base64'),
  }
}

const res = await fetch(
  'https://json.astrologyapi.com/v1/sun_sign_prediction/daily/aries',
  {
    method: 'POST',
    headers: { ...authHeaders(), 'Content-Type': 'application/json' },
    body: JSON.stringify({ timezone: 5.5 }),
  },
)
if (!res.ok) {
  throw new Error(`Request failed with ${res.status}: ${await res.text()}`)
}
const data = await res.json()
console.log(data.profession)

And in Python:

# daily.py - pip install requests
import os
import requests

TOKEN = os.environ.get("ASTROLOGY_ACCESS_TOKEN")

# Use the access token if set, otherwise the user ID and API key.
if TOKEN:
    auth_args = {"headers": {"x-astrologyapi-key": TOKEN}}
else:
    auth_args = {
        "auth": (os.environ["ASTROLOGY_USER_ID"], os.environ["ASTROLOGY_API_KEY"])
    }

response = requests.post(
    "https://json.astrologyapi.com/v1/sun_sign_prediction/daily/aries",
    json={"timezone": 5.5},
    timeout=15,
    **auth_args,
)
response.raise_for_status()  # stops on any non-2xx status
data = response.json()
print(data["profession"])

Sample response, trimmed:

{
  "profession": "At work, it's a day to tread carefully. Your interactions could be prone to misinterpretations, thanks to the Moon's angle with Jupiter. It's crucial to double-check any information you share or receive. A seemingly minor detail overlooked could lead to significant delays or errors. Focus on clarity in your communications and ensure all parties are on the same page before moving forward with projects. Patience and precision will guide you through the day without major mishaps.",
  "luck": "Luck today is a mixed bag. It's not about finding a pot of gold at the end of the rainbow but more about recognizing the small blessings scattered throughout your day. Pay attention to these little wins; they are your true lucky moments."
  // ...also personal_life, health, emotions and travel
}

Each field is a ready-to-show paragraph. You can show all six, or pick the ones that fit your screen.

Show all 12 signs on your website

A daily horoscope page usually lists all 12 signs. Don't call us each time a visitor opens the page. Fetch each sign once a day on your server, save the JSON and serve the saved copy.

  • It saves credits. You make 12 calls a day, no matter how many visitors you have.
  • Everyone sees the same text. All Leo readers get the same Leo horoscope all day.
  • Your page stays fast. It reads a local file and never waits on a network call.

A daily job that fetches all 12 signs

This script loops the 12 signs and saves them to data/horoscopes.json. If any call fails, it stops and keeps yesterday's file in place.

// fetch-horoscopes.mjs - Node 18+. Run once a day, for example from cron.
// It calls us 12 times (one per sign) and saves the result to one file.
import { mkdir, writeFile, rename } from 'node:fs/promises'

const BASE_URL = 'https://json.astrologyapi.com/v1'
// UTC offset of your readers, in hours. Example: -5 for New York in winter.
const TIMEZONE = Number(process.env.HOROSCOPE_TIMEZONE ?? 5.5)

const SIGNS = [
  'aries', 'taurus', 'gemini', 'cancer', 'leo', 'virgo',
  'libra', 'scorpio', 'sagittarius', 'capricorn', 'aquarius', 'pisces',
]

// Uses your access token if set, otherwise your user ID and API key.
function authHeaders() {
  const token = process.env.ASTROLOGY_ACCESS_TOKEN
  if (token) return { 'x-astrologyapi-key': token }
  const userId = process.env.ASTROLOGY_USER_ID
  const apiKey = process.env.ASTROLOGY_API_KEY
  if (!userId || !apiKey) {
    throw new Error('Set ASTROLOGY_ACCESS_TOKEN, or ASTROLOGY_USER_ID and ASTROLOGY_API_KEY')
  }
  return {
    Authorization: 'Basic ' + Buffer.from(userId + ':' + apiKey).toString('base64'),
  }
}

async function getDaily(sign) {
  const res = await fetch(`${BASE_URL}/sun_sign_prediction/daily/${sign}`, {
    method: 'POST',
    headers: { ...authHeaders(), 'Content-Type': 'application/json' },
    body: JSON.stringify({ timezone: TIMEZONE }),
  })
  if (!res.ok) {
    throw new Error(`${sign} failed with ${res.status}: ${await res.text()}`)
  }
  return res.json()
}

// The readers' calendar date as YYYY-MM-DD.
function readerDate(offsetHours) {
  return new Date(Date.now() + offsetHours * 3600 * 1000)
    .toISOString()
    .slice(0, 10)
}

const result = { date: readerDate(TIMEZONE), timezone: TIMEZONE, signs: {} }
for (const sign of SIGNS) {
  result.signs[sign] = await getDaily(sign)
}

// If any sign failed, the script stopped above and the old file stays.
// Write a temp file, then rename it, so readers never get half a file.
await mkdir('data', { recursive: true })
await writeFile('data/horoscopes.tmp.json', JSON.stringify(result))
await rename('data/horoscopes.tmp.json', 'data/horoscopes.json')
console.log(`Saved 12 signs for ${result.date}`)

Run it once a day with cron (a tool that runs commands on a schedule). Make sure the cron job can see your auth environment variables.

# crontab: run at 00:05 server time every day
5 0 * * * cd /srv/horoscopes && node fetch-horoscopes.mjs >> fetch.log 2>&1

Then serve the file to your page. This small server never calls our API, so visitors cost you nothing.

// server.mjs - serves the cached file. It never calls our API.
import { createServer } from 'node:http'
import { readFile } from 'node:fs/promises'

createServer(async (req, res) => {
  if (req.url !== '/horoscopes.json') {
    res.writeHead(404).end()
    return
  }
  try {
    const body = await readFile('data/horoscopes.json')
    res.writeHead(200, {
      'Content-Type': 'application/json',
      'Cache-Control': 'public, max-age=600',
    })
    res.end(body)
  } catch (err) {
    console.error(err)
    res.writeHead(503, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ error: 'Horoscopes are not ready yet' }))
  }
}).listen(3000)

Your page fetches /horoscopes.json and reads signs.leo.profession, and so on.

Get the day right with timezone

timezone is a UTC offset in hours, as a decimal. For example, 5.5 is India and -5 is New York in winter. If you leave it out, we use 5.5.

  • Send the offset of the readers who will see the text, not the offset of your server.
  • Run the job just after midnight in that timezone. Cron uses your server's clock, so convert the time if they differ.
  • Offsets change with daylight saving time. New York is -5 in winter and -4 in summer. Work out the offset each day rather than hard-coding it.
  • If your readers live in many timezones, cache one file per timezone. Key it by timezone and date.

For more on UTC offsets and daylight saving, read Timezones, DST, and birth data.

Yesterday and tomorrow tabs

Many horoscope apps show three tabs: Yesterday, Today and Tomorrow. Use sun_sign_prediction/daily/previous/:zodiacName for yesterday and sun_sign_prediction/daily/next/:zodiacName for tomorrow. They take the same inputs as today's endpoint.

Their response has a different shape. We put the six fields inside prediction and add prediction_date in day-month-year form:

{
  "status": true,
  "sun_sign": "aries",
  "prediction_date": "21-3-2024",
  "prediction": {
    "luck": "The Moon's trine to the North Node enhances your intuitive sense, making today favorable for trusting your instincts. Your gut feelings could lead you to unexpected opportunities or decisions that align well with your path forward. Listen closely to your inner voice."
    // ...also personal_life, profession, health, emotions and travel
  }
}

This helper reads all three tabs and returns one flat shape. Add it to the daily job and cache 36 entries (12 signs times 3 days) instead of 12.

// Today, tomorrow and yesterday for one sign.
// Add this to fetch-horoscopes.mjs. It reuses BASE_URL, TIMEZONE
// and authHeaders() from that file.
const PATHS = {
  today: (sign) => `sun_sign_prediction/daily/${sign}`,
  tomorrow: (sign) => `sun_sign_prediction/daily/next/${sign}`,
  yesterday: (sign) => `sun_sign_prediction/daily/previous/${sign}`,
}

async function getDay(sign, tab) {
  const res = await fetch(`${BASE_URL}/${PATHS[tab](sign)}`, {
    method: 'POST',
    headers: { ...authHeaders(), 'Content-Type': 'application/json' },
    body: JSON.stringify({ timezone: TIMEZONE }),
  })
  if (!res.ok) throw new Error(`${tab} ${sign} failed with ${res.status}`)
  const data = await res.json()
  // Next and previous wrap the six fields in "prediction". Handle both shapes.
  return { date: data.prediction_date ?? null, ...(data.prediction ?? data) }
}

Weekly and monthly views

horoscope_prediction/weekly/:zodiacName returns the week's horoscope. Here timezone is required. We return week_start_date and a list of paragraphs:

{
  "status": true,
  "sun_sign": "aries",
  "week_start_date": "14-6-2026",
  "prediction": [
    "While this plays out in your work life, team moods shift just as fast. The early week feels scattered, with people sending mixed signals or pulling away without warning. As the Moon hits your creative house by midweek, you’ll want center stage or at least clear recognition for what you’ve done. It’s a strong week to pitch ideas, just watch the urge to dominate every conversation."
    // ...more paragraphs
  ]
}

horoscope_prediction/monthly/:zodiacName works the same way. We return prediction_month and a list of paragraphs:

{
  "status": true,
  "sun_sign": "aries",
  "prediction_month": "January",
  "prediction": [
    "This is not a time for frivolous goals, these will quickly go by the wayside, this is a time when your most important goals must become your priority."
    // ...more paragraphs
  ]
}

Show each array item as its own paragraph. Cache weekly results by week_start_date and monthly results by month. Fetch them once at the start of each week or month, not every day.

Push notifications and email

A morning push or email is a common feature. The rule is the same as for the website: reuse the cached text. Never call us once per user.

  • Group your users by sign and by timezone.
  • For each group, send at a set local time, such as 8:00. Read the text from the cache you built for that timezone.
  • A thousand Leo users in one timezone still cost one call.
  • For short messages, use one field, such as luck. Or use the consolidated endpoint, which gives one paragraph.
{
  "status": true,
  "sun_sign": "aries",
  "prediction_date": "17-6-2017",
  "prediction": "You are feeling rather good and it seems that you can place the pulse of success easily. You will be profusely passionate about things today. Your rapport with relatives and associates will be good. Go out for a fun filled evening and you are likely to become the life and soul of the celebrations. Following your instincts today can lead to great things in your personal life and relationships. Decode the implications of your imagination. It will bring luck and happiness."
}

Our Telegram horoscope bot guide builds a full version of this in Python, with subscriptions and a daily send.

Sign-based or personalised horoscopes

A sign-based horoscope needs only a sign. A personalised one needs the user's birth details, so two people with the same sun sign can get different text. Pick based on what your users give you.

EndpointInputsWhat we return
sun_sign_prediction/daily (this guide)Sign onlyThe same daily text for everyone with that sign. English.
daily_nakshatra_prediction (Vedic)Birth date, time, place and tzoneA daily prediction from the user's birth Moon sign and nakshatra (one of 27 star groups the Moon passes through). Same six fields. Languages: en, hi, bn, ta, te, ml, kn and ma.
natal_transits/daily (Western)Birth details plus house_typeToday's transits (where planets are now, compared with the birth chart). Data, not written text.
personal_day_prediction (numerology)date, month, year, full_nameA personal day number and a written report.

Personalised results can't be shared between users, so you cache them per user, not per sign. Start with sign-based horoscopes if users only tell you their sign. Move to birth-chart endpoints once they give you a birth date, time and place. To build that, read the Kundli API integration guide or the Western birth chart guide. You can also browse our Vedic astrology API and Western astrology API pages.

Plans and credits

Our horoscope endpoints are part of the Horoscope suite. Plans start at $89 a month, or ₹3,500 in India. See horoscope pricing for the full plan list. You can also pay as you go from a wallet, as explained in the pay-as-you-go guide. To check what each call costs, use the credits calculator. For a product overview, visit the horoscope API page.

Try the daily horoscope API

Every new account gets 150 free credits, so you can make your first call today.

Frequently asked questions

Is there a free horoscope API?

Every new account gets 150 free credits, so you can test our horoscope endpoints before you pay. After that, pick a plan or top up your wallet from $5 (₹500 in India). The credits calculator shows what each call costs.

What does the daily horoscope API return?

We return JSON. The daily endpoint gives six text fields for one zodiac sign: personal_life, profession, health, emotions, travel and luck. The consolidated endpoint gives one paragraph instead.

How often does the daily horoscope change?

Once per calendar day for each sign. Everyone with the same sign gets the same text on the same day. So fetch each sign once a day and cache it.

What timezone value should I send?

Send the UTC offset of your readers in hours, as a decimal. For example, 5.5 for India or -5 for New York in winter. If you leave it out, we use 5.5. The weekly endpoint requires it.

Which languages are the horoscopes in?

Our sign-based horoscope endpoints return English. For Hindi and other Indian languages, use the daily_nakshatra_prediction endpoint with the Accept-Language header.

Can I call the horoscope API from the browser?

No. We do not send CORS headers, and your access token or API key must stay secret. Call us from your server, cache the result, and serve that to your page.

For AI agents

  • Base URL https://json.astrologyapi.com/v1. All calls are POST with a JSON body, server-side only.
  • Auth: header x-astrologyapi-key: <access token> (free trial and wallet), or HTTP Basic with user ID and API key (plan subscribers).
  • Today: /sun_sign_prediction/daily/:zodiacName. Returns personal_life, profession, health, emotions, travel, luck.
  • Tomorrow and yesterday: add /next/ or /previous/ before the sign. The six fields are under prediction, with prediction_date.
  • One paragraph: /sun_sign_consolidated/daily/:zodiacName. Weekly: /horoscope_prediction/weekly/:zodiacName (timezone required). Monthly: /horoscope_prediction/monthly/:zodiacName.
  • zodiacName is a lowercase sign name. Body: { "timezone": 5.5 }, a UTC offset in hours. Default 5.5.
  • Fetch once per sign, per timezone, per day. Cache and serve the cached copy to every user.
  • Personalised daily text from birth details: Vedic /daily_nakshatra_prediction.