Prayer Times & Content API
Pull your mosque's prayer timetable — and now Qur'an verses, Hadith, Du'ās, announcements and events — straight into your own website, app, spreadsheet or a scheduled script, without logging into the portal. Written for anyone comfortable with a command line or a little code.
Base URL:
https://hayyalasalah.co.uk/prayer_times_api.php
- GET — download your timetable, or pull content (Qur'an, Hadith, Du'ā, announcements, events, panels)
- POST (or PUT) — upload / update your timetable
- Responses are JSON (except CSV downloads). HTTPS only.
- Browser-friendly: content requests may be called directly from a web page — cross-origin (CORS) requests are allowed from any site (see §5).
Your API key or login is tied to a single mosque, so you never send a mosque id. The endpoint always reads and writes your timetable only.
1. Authentication
Every request must be authenticated, and the credential goes in the Authorization header — never in the URL (that would leak it into logs). There are two ways to authenticate.
Option A — API key (recommended for scripts)
Open the portal
Sign in and open 🔑 API Keys in the left-hand menu.
Generate a key
Click Generate API key, choose Read & write (or Read only), and copy it now — the key is shown only once.
Send it as a Bearer token
On every request, add the header:
Authorization: Bearer hpk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
You can create several keys (e.g. one per integration) and revoke any of them at any time from the same page. Keys are stored hashed — if one is lost, revoke it and generate a new one.
Option B — your MySQL login
If your mosque already has a MySQL username and password, use those directly with HTTP Basic authentication — no key needed. With curl that is just -u user:password:
curl -u YOUR_MYSQL_USER:YOUR_PASSWORD \
"https://hayyalasalah.co.uk/prayer_times_api.php?date=2026-07-01"
MySQL logins always have read + write access.
2. Downloading prayer times
Send a GET request and choose the date window with one of these parameters:
| Parameter | Meaning | Example |
|---|---|---|
| (none) | Current calendar year | ? |
date | A single day | ?date=2026-07-01 |
from + to | Inclusive range (max 750 days) | ?from=2026-01-01&to=2026-03-31 |
year | A whole year | ?year=2026 |
format=csv | CSV instead of JSON | ?year=2026&format=csv |
One day as JSON:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://hayyalasalah.co.uk/prayer_times_api.php?date=2026-07-01"
A full year as a CSV file:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://hayyalasalah.co.uk/prayer_times_api.php?year=2026&format=csv" \
-o my_timetable_2026.csv
Sample JSON response:
{
"ok": true,
"mosque_id": "your_mosque",
"from": "2026-07-01",
"to": "2026-07-01",
"count": 1,
"prayer_times": [
{
"Date": "2026-07-01", "Day": "Wednesday",
"Fajr_Begins": "02:49:00", "Fajr_Jamaat": "03:10:00",
"Sunrise": "04:47:00",
"Zohr_Begins": "13:10:00", "Zohr_Jamaat": "13:30:00",
"Asr_Begins": "18:40:00", "Asr_Jamaat": "19:30:00",
"Magrib_Begins": "21:25:00", "Magrib_Jamaat": "21:25:00",
"Isha_Begins": "22:41:00", "Isha_Jamaat": "22:50:00",
"Jumah_1": "13:30:00", "Jumah_2": "14:00:00", "Jumah_3": null
}
]
}
3. Uploading prayer times
Send a POST request with your data as JSON or CSV (set Content-Type to match).
Rows are matched by Date. Only the columns you send are changed — anything you leave out keeps its current value. New dates are added; dates you don't mention are untouched. Up to 750 rows per request. Each upload also snapshots the affected year on the server so it can be rolled back.
Writable columns
Day,
Fajr_Begins, Fajr_Jamaat,
Imsak_Begins, Sunrise,
Zohr_Begins, Zohr_Jamaat,
Asr_Begins, Asr_Jamaat,
Magrib_Begins, Magrib_Jamaat,
Isha_Begins, Isha_Jamaat,
Midnight,
Jumah_1, Jumah_2, Jumah_3
Dateis required on every row, formattedYYYY-MM-DD.- Times may be
HH:MMorHH:MM:SS(24-hour).05:15and05:15:00are both accepted. - Unknown column names are ignored; blank values are skipped (not written).
JSON upload
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '[
{"Date":"2026-07-01","Fajr_Jamaat":"03:10","Zohr_Jamaat":"13:30","Isha_Jamaat":"22:50"},
{"Date":"2026-07-02","Fajr_Jamaat":"03:12","Isha_Jamaat":"22:49"}
]' \
"https://hayyalasalah.co.uk/prayer_times_api.php"
You may also send an object like {"prayer_times": [ ... ]} instead of a bare array.
CSV upload
The first line must be the header row and include Date:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: text/csv" \
--data-binary $'Date,Fajr_Jamaat,Isha_Jamaat\n2026-07-01,03:10,22:50\n2026-07-02,03:12,22:49' \
"https://hayyalasalah.co.uk/prayer_times_api.php"
To upload an existing CSV file, point --data-binary at it:
curl -X POST \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: text/csv" \
--data-binary @my_timetable.csv \
"https://hayyalasalah.co.uk/prayer_times_api.php"
CSV upload with your MySQL login (Basic auth)
Every example on this page also works with your MySQL username and password instead of an API key — just swap the Authorization: Bearer header for curl's -u USER:PASSWORD. For a CSV file:
curl -X POST \
-u YOUR_MYSQL_USER:YOUR_PASSWORD \
-H "Content-Type: text/csv" \
--data-binary @my_timetable.csv \
"https://hayyalasalah.co.uk/prayer_times_api.php"
Or a quick inline test (uploads to a throwaway date so your live timetable is untouched):
curl -X POST \
-u YOUR_MYSQL_USER:YOUR_PASSWORD \
-H "Content-Type: text/csv" \
--data-binary $'Date,Fajr_Jamaat,Isha_Jamaat\n2099-12-31,03:10,22:50' \
"https://hayyalasalah.co.uk/prayer_times_api.php"
Send the CSV with --data-binary (for a file, --data-binary @file.csv). Plain -d strips the line breaks, which merges every row into one line and breaks the upload. The header row must be first and include Date.
Sample upload response:
{
"ok": true,
"mosque_id": "your_mosque",
"rows_written": 2,
"inserted": 1,
"updated": 1,
"failed": 0
}
After a successful upload your screens and apps pick up the change automatically — the cache is refreshed for you.
4. Content resources (Qur'an, Hadith, Du'ā, announcements, events)
Besides prayer times, the same endpoint can serve read-only content for you to display on your website or app. Add a resource parameter to a GET request:
GET …/prayer_times_api.php?resource=NAME
| resource | What you get | Scope |
|---|---|---|
quran | A Qur'an verse (Arabic + English + reference) | Shared library |
hadith | A Hadith (Arabic + English + source + narrator) | Shared library |
dua | A Du'ā (title, Arabic, transliteration, English, occasion) | Shared library |
announcements | Your mosque's active ticker announcements | Your mosque |
events | Your mosque's upcoming events | Your mosque |
panels | Your enabled custom text panels | Your mosque |
Options for quran, hadith and dua
| Parameter | Meaning | Example |
|---|---|---|
| (none) | Daily — a stable item that stays the same all day, then rotates. Great for a "verse of the day". | ?resource=quran |
mode=random | A different random item on every request | ?resource=hadith&mode=random |
id=N | One specific item by its id | ?resource=dua&id=132 |
limit=N | How many items to return (1–50, default 1) | ?resource=quran&limit=3 |
announcements and events always return your current items (default up to 20, limit up to 50); they need no mode. panels returns whatever custom panels you've enabled in the portal.
Every response has the same shape
{
"ok": true,
"resource": "quran",
"count": 1,
"items": [ … ],
"server_time": "2026-07-02T21:47:46+01:00"
}
Verse of the day:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://hayyalasalah.co.uk/prayer_times_api.php?resource=quran"
{
"ok": true, "resource": "quran", "count": 1, "mode": "daily",
"items": [
{
"id": 1025,
"arabic": "إِنَّ ٱلَّذِينَ كَفَرُوا۟ …",
"english": "Indeed, those who disbelieve …",
"surah_name": "Al-Baqarah", "surah_number": 2, "verse_number": 6,
"reference": "Qur'an 2:6"
}
]
}
Three random Hadith:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://hayyalasalah.co.uk/prayer_times_api.php?resource=hadith&mode=random&limit=3"
Your announcements:
curl -H "Authorization: Bearer YOUR_API_KEY" \
"https://hayyalasalah.co.uk/prayer_times_api.php?resource=announcements"
{
"ok": true, "resource": "announcements", "count": 1,
"items": [
{ "title": "Eid Mubarak", "message": "Eid prayer will be held at 8:00 AM …" }
]
}
Upcoming events return title, description, event_date, event_time and location; panels return slot, title and body. If a mosque has none configured you simply get "count": 0 and an empty items list — never an error.
These resources are GET only — there is nothing to upload. A Read only API key is all you need, and it's the right choice for anything you put on a public website (see below).
5. Adding it to your website
Because content requests are read-only and safe to call from a browser, you can drop them straight into a web page. Cross-origin (CORS) requests are allowed from any domain, so this works on any site — WordPress, Wix, a static HTML page, anything.
Anything in a web page's JavaScript is visible to visitors. Generate a Read only key for your site — it can fetch content but can never change your prayer times. Never put a read & write key (or your MySQL password) in a public page.
Copy-paste "Verse of the Day" widget. Paste this anywhere in your page's HTML and set your key:
<div id="hayya-verse" style="max-width:640px;margin:1em auto;text-align:center;
font-family:system-ui,sans-serif">Loading…</div>
<script>
const HAYYA_KEY = "hpk_your_read_only_key_here"; // Read-only key from the portal
const HAYYA_API = "https://hayyalasalah.co.uk/prayer_times_api.php";
fetch(HAYYA_API + "?resource=quran", { headers: { "X-Api-Key": HAYYA_KEY } })
.then(r => r.json())
.then(d => {
const v = d.items[0];
document.getElementById("hayya-verse").innerHTML =
'<p dir="rtl" lang="ar" style="font-size:1.6em;line-height:2">' + v.arabic + '</p>' +
'<p style="font-style:italic">' + v.english + '</p>' +
'<p style="opacity:.7">— ' + v.reference + '</p>';
})
.catch(() => { document.getElementById("hayya-verse").textContent = "Unavailable"; });
</script>
Announcements list. The same pattern shows your mosque's live announcements:
<ul id="hayya-news"></ul>
<script>
fetch("https://hayyalasalah.co.uk/prayer_times_api.php?resource=announcements",
{ headers: { "X-Api-Key": "hpk_your_read_only_key_here" } })
.then(r => r.json())
.then(d => {
document.getElementById("hayya-news").innerHTML =
d.items.map(a => "<li><strong>" + a.title + "</strong> — " + a.message + "</li>").join("");
});
</script>
Use resource=quran (daily mode) rather than mode=random so every visitor sees the same verse and it changes once a day. For Arabic, set dir="rtl" and a font that supports Arabic. Both X-Api-Key: KEY and Authorization: Bearer KEY headers work.
6. A quick Python example
import requests
BASE = "https://hayyalasalah.co.uk/prayer_times_api.php"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
# Download July 2026
r = requests.get(BASE, headers=HEADERS, params={"from": "2026-07-01", "to": "2026-07-31"})
print(r.json()["count"], "days")
# Upload two days
rows = [
{"Date": "2026-07-01", "Fajr_Jamaat": "03:10", "Isha_Jamaat": "22:50"},
{"Date": "2026-07-02", "Fajr_Jamaat": "03:12", "Isha_Jamaat": "22:49"},
]
r = requests.post(BASE, headers=HEADERS, json=rows)
print(r.json())
# Pull the daily Qur'an verse
r = requests.get(BASE, headers=HEADERS, params={"resource": "quran"})
print(r.json()["items"][0]["reference"])
7. Response codes
| Code | Meaning |
|---|---|
200 | Success |
400 | Bad request — malformed date/time or invalid JSON/CSV. The error field explains what's wrong. |
401 | Missing or invalid credentials |
403 | Your key is read-only but you tried to upload |
413 | Payload too large (over 2 MB, or more than 750 rows) |
429 | Rate limit hit — wait and retry (see the Retry-After header) |
503 | Service temporarily unavailable — retry shortly |
On any error, the body looks like this, and nothing is written if validation fails — fix the row and resend:
{ "ok": false, "error": "Row 3: invalid time for Fajr_Jamaat ('25:99'). Use HH:MM or HH:MM:SS." }
8. Tips & good practice
How can I test safely without disturbing my live timetable?
Upload to a throwaway future date such as 2099-12-31, confirm it with a GET, then overwrite or ignore it. Your real dates are never touched unless you send them.
Do I have to send every column every time?
No — send only the columns you're changing. For example, a CSV of just Date,Fajr_Jamaat updates Fajr Jamā'ah and leaves everything else exactly as it was.
Should I use an API key or my MySQL login?
Prefer an API key for automated scripts — it's scoped and revocable, so you can rotate it without changing your database password. Use the MySQL login only for quick manual checks.
Can I show the verse of the day / announcements on my website?
Yes. Generate a Read only key and use the browser snippets in §5. Content requests allow cross-origin (CORS) calls from any domain, so they work on any website. Keep read & write keys off public pages.
Will the daily verse be the same for everyone?
Yes — resource=quran (and hadith/dua) in the default daily mode returns a fixed item that's identical for every visitor and rotates once per day. Use mode=random if you'd rather it change on every page load.
My key was exposed. What now?
Go to 🔑 API Keys in the portal, revoke it, and generate a new one. Revocation takes effect immediately.
How big can an upload be?
Up to 750 rows (about two years of dates) and 2 MB per request. For a full multi-year import, send it in batches — for example one month or one year at a time.
Treat your API key like a password. Never put it in a URL, a screenshot, or a public code repository. If in doubt, revoke and regenerate.