API and agent docs
Everything a script or an AI assistant needs to use SolatCal: the calendar feed, the JSON endpoints and the MCP server. No key and no account. The same text is at llms.txt, and the OpenAPI spec describes the HTTP API.
Turns official JAKIM e-Solat prayer times for Malaysia into an iCalendar (.ics) feed that any calendar app can subscribe to. 60 zones, no account, no key, free. Unofficial: not affiliated with JAKIM.
All times are Asia/Kuala_Lumpur (UTC+08:00, no DST) and come from JAKIM e-Solat unchanged. SolatCal performs no astronomical calculation of its own.
/api/* and /mcp allow 300 requests a minute per client IP. Static pages are exempt. Responses state the limit in RateLimit-Policy and X-RateLimit-Limit. Exceeding it returns HTTP 429 with Retry-After.
How the times are checked
SolatCal copies JAKIM's published times and calculates none of its own, so there is no calculation method or adjustment that could differ from JAKIM. An automated test suite covers every rule that turns a JAKIM day into events. The published feeds are also checked end to end: a separate script downloads JAKIM's year for every zone and the live feed for the same zone, parses both independently, and compares every event with JAKIM's time for that date and prayer. The latest check, on 2026-09-25 (UTC), compared all 34920 events in the feeds for all 60 zones, from 2026-09-26 to 2026-12-31, with JAKIM's published times: every event matched to the minute and none were missing. See About.
Pages
Every page below also answers Accept: text/markdown with a Markdown version at the same address (Content-Type: text/markdown, Vary: Accept), 404s included.
- English: the feed builder.
- Bahasa Malaysia: the same builder in Malay.
- Prayer times by zone and Waktu solat mengikut zon: every zone, by state.
- One page per zone and language, for example https://solatcal.umarrasydan.com/prayer-times/sgr01 and https://solatcal.umarrasydan.com/ms/waktu-solat/sgr01: today's times, the month's timetable (
?month=YYYY-MMfor another month of the current year) and a builder set to that zone. - About: where the times come from and how they are checked. Privacy: what is processed and where. Contact: how to reach the maker and report a wrong time. All three also in Malay.
- API docs: this document as a web page.
Calendar feed
GET https://solatcal.umarrasydan.com/api/feed.ics?zone=<ZONE>&...
Returns text/calendar. Subscribe to the URL for a feed that updates itself, or add &download=1 for a one-off file. Swap the scheme for webcal: to make Apple Calendar and most desktop clients subscribe directly. Google Calendar's subscribe deep link also needs the webcal:// form.
| Parameter | Values | Default | Meaning |
|---|---|---|---|
zone | one of the 60 zone codes below | required | Which JAKIM zone |
period | month, quarter, year | year | Date range for a one-off download. month and quarter run forward from today; year runs to 31 December. Subscriptions always carry the rest of the year regardless |
prayers | comma separated, any of fajr, syuruk, dhuhr, asr, maghrib, isha | fajr,dhuhr,asr,maghrib,isha | Which prayers become events |
align | exact, early5, early10, block15 | exact | Event start: at the solat time, 5 or 10 minutes before, or snapped down to the containing 15 minute block |
duration | integer 5 to 120 | 15 | Event length in minutes. With block15 the end also rounds up to the next quarter hour |
busy | busy, free | busy | Sets TRANSP to OPAQUE or TRANSPARENT |
alarm | none, 0, 5, 10 | none | Display reminder, that many minutes before the start |
ramadan | 0, 1 | 0 | With 1, days JAKIM dates to Ramadan gain an Imsak event from imsak to Subuh, and the Maghrib event is titled as iftar |
hijri | none, major, daily | none | All-day hijri date events, marked free: major for dates such as Awal Ramadan and Hari Raya Aidilfitri, daily for every day |
lang | en, ms | en | Language of the labels inside the calendar. Prayer names are Malay either way |
download | 1 | off | Adds a Content-Disposition: attachment header |
Any unrecognised value returns HTTP 400 with a JSON body of the form {"error": "...", "status": 400} naming the offending parameter.
Examples
Five daily prayers for Kuala Lumpur, on time, 15 minutes:
https://solatcal.umarrasydan.com/api/feed.ics?zone=WLY01
Selangor (Gombak and Petaling), snapped to 15 minute blocks, 30 minutes, marked free, 10 minute reminder, Malay labels:
https://solatcal.umarrasydan.com/api/feed.ics?zone=SGR01&align=block15&duration=30&busy=free&alarm=10&lang=ms
Kuching with Ramadan events and the major hijri dates:
https://solatcal.umarrasydan.com/api/feed.ics?zone=SWK08&ramadan=1&hijri=major
Download the next three months for Johor Bahru including Syuruk:
https://solatcal.umarrasydan.com/api/feed.ics?zone=JHR02&period=quarter&prayers=fajr,syuruk,dhuhr,asr,maghrib,isha&download=1
Subscribe from Apple Calendar:
webcal://solatcal.umarrasydan.com/api/feed.ics?zone=WLY01
Event shape
One VEVENT per prayer per day. SUMMARY uses the Malay names Subuh, Syuruk, Zohor, Asar, Maghrib, Isyak; on Fridays Zohor is titled Jumaat. UID is <zone>-<YYYYMMDD>-<prayer>@<host> and never changes, so re-importing updates events instead of duplicating them. DESCRIPTION always carries the exact JAKIM time, the zone, the hijri date and a source link, even when align has moved the event start.
With ramadan=1, Ramadan days add an Imsak event (UID suffix imsak) that starts at imsak, ends at Subuh and ignores align. The Maghrib event's title becomes Maghrib (Iftar) or Maghrib (Berbuka). With hijri, all-day events (UID suffix hijri) carry the hijri date. On dates such as Hari Raya the occasion name comes first, as in Hari Raya Aidilfitri ยท 1 Syawal 1448. They are always TRANSPARENT and never carry a reminder.
Other JSON endpoints
The HTTP API is also described as OpenAPI 3.1 at https://solatcal.umarrasydan.com/openapi.json, and GET https://solatcal.umarrasydan.com/api lists every endpoint with links to these docs.
GET https://solatcal.umarrasydan.com/api/zones- every zone code mapped to its districts.GET https://solatcal.umarrasydan.com/api/places- towns and districts per zone with coordinates, which the pages use to find a zone by name or by the visitor's location.GET https://solatcal.umarrasydan.com/api/preview?zone=<ZONE>- today's times for one zone, already run through the samealignanddurationrules as the feed. Accepts the same parameters as the feed, includingramadanandhijri(all-day events come back underallDay). Also carries today'simsak, whether today is in Ramadan, and tomorrow's raw times undertomorrow, which isnullon 31 December.GET https://solatcal.umarrasydan.com/api/health- service and upstream status.
MCP server
POST https://solatcal.umarrasydan.com/mcp speaks Model Context Protocol over JSON-RPC 2.0. It is stateless Streamable HTTP: no session id, no SSE required, responses are application/json. GET /mcp returns 405. Bodies larger than 32 KB return 413. Batched JSON-RPC arrays are refused.
Handled methods: initialize, notifications/* (202, no body), ping, tools/list, tools/call. Anything else is JSON-RPC -32601, and a tools/call for a tool that does not exist is -32602.
| Tool | Purpose |
|---|---|
list_zones | The 60 zones grouped by state, optionally filtered by state name or zone prefix |
get_prayer_times | One day's times for one zone, plus the hijri date |
get_calendar_feed | A validated feed URL, webcal URL, download URL and a plain-language summary. Does not fetch times |
Bad tool input comes back as a normal result with isError: true and a message naming the offending parameter, not as a protocol error. get_calendar_feed validates through the same rules as the HTTP feed.
curl -sX POST https://solatcal.umarrasydan.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Zones
60 zone codes. A few common ones:
WLY01Kuala Lumpur, PutrajayaSGR01Gombak, Petaling, Sepang, Hulu Langat, Hulu Selangor, S.AlamJHR02Johor Bahru, Kota Tinggi, Mersing, KulaiPNG01Seluruh Negeri Pulau PinangSWK09Zon Khas (Kampung Patarikan)
The full list is at https://solatcal.umarrasydan.com/api/zones. Codes are three letters for the state (JHR Johor, KDH Kedah, KTN Kelantan, MLK Melaka, NGS Negeri Sembilan, PHG Pahang, PLS Perlis, PNG Pulau Pinang, PRK Perak, SBH Sabah, SGR Selangor, SWK Sarawak, TRG Terengganu, WLY Wilayah Persekutuan) plus a two digit number.
Attribution
Prayer times are the property of JAKIM e-Solat: https://www.e-solat.gov.my/index.php?siteId=24&pageId=24 SolatCal only reformats them, and is not affiliated with or endorsed by JAKIM. Made by Umar Rasydan.