← Blog
🕌

A Prayer Reminder App with Zero API Cost

Tutorial · 5 min read

Prayer times and holidays are free forever — no API key at all. Build a complete app without spending a rupiah on API calls.

Two endpoints on API.MY.ID are completely free and need no API key: prayer times and national holidays. No quota, no points, no signup. This article builds a simple prayer reminder app on top of them.

The first call

No headers, no auth — just a GET:

curl "https://v1.api.my.id/sholat?city=jakarta"
{
  "status": "success",
  "data": {
    "city": { "slug": "jakarta", "name": "Jakarta" },
    "date": "2026-07-09",
    "timezone": "WIB",
    "jadwal": {
      "imsak": "04:31", "subuh": "04:41", "terbit": "06:04", "dhuha": "06:28",
      "dzuhur": "12:00", "ashar": "15:20", "maghrib": "17:53", "isya": "19:06"
    }
  }
}

How the times are computed

Prayer times are not rows in a table — they are computed from the sun's position for the requested coordinates and date. We use the angle conventions commonly used by Kemenag: Fajr at −20°, Isha at −18°, sunrise and maghrib at −0.833° (accounting for atmospheric refraction and the solar radius), and Asr by the Shafi'i method. A +2 minute ihtiyat (safety margin) is added to Dhuhr and Maghrib.

The practical upshot: 54 cities are supported with correct time zones (WIB, WITA, WIT), and you can request any date — yesterday, today, or Ramadan next year.

Scheduling notifications

The right pattern: fetch the schedule once a day, then schedule local notifications. Do not poll the API every minute — the schedule does not change.

const PRAYERS = ['subuh', 'dzuhur', 'ashar', 'maghrib', 'isya'];

async function scheduleToday(city = 'jakarta') {
  const res = await fetch(`https://v1.api.my.id/sholat?city=${city}`);
  const { data } = await res.json();

  for (const name of PRAYERS) {
    const [h, m] = data.jadwal[name].split(':').map(Number);
    const at = new Date();
    at.setHours(h, m, 0, 0);

    const delay = at - Date.now();
    if (delay <= 0) continue;               // already passed today

    setTimeout(() => {
      new Notification(`Time for ${name}`, {
        body: `${data.jadwal[name]} ${data.timezone} — ${data.city.name}`,
      });
    }, delay);
  }
}

// run on app open, and at midnight
scheduleToday();
💡 For a production app, use the platform notification API (Service Worker on web, WorkManager on Android, UNUserNotificationCenter on iOS) so reminders survive the app being closed. The setTimeout above only illustrates the idea.

Ramadan: imsak and iftar

For sahur and iftar timers, the two fields you need are already in the same response: imsak and maghrib. Since you can request any date, the whole Ramadan calendar can be fetched once and cached locally:

async function ramadanCalendar(city, start, days = 30) {
  const out = [];
  for (let i = 0; i < days; i++) {
    const t = new Date(start);
    t.setDate(t.getDate() + i);
    const date = t.toISOString().slice(0, 10);

    const res = await fetch(`https://v1.api.my.id/sholat?city=${city}&date=${date}`);
    const { data } = await res.json();
    out.push({ date, imsak: data.jadwal.imsak, iftar: data.jadwal.maghrib });
  }
  return out;   // persist to localStorage / SQLite
}

Bonus: the holiday calendar

The second free endpoint rounds out any calendar app. It returns national holidays and joint-leave days per the official SKB decree, with flags distinguishing the two:

curl "https://v1.api.my.id/holidays/upcoming?limit=3"

Because both are free and keyless, this entire app can run with no backend at all — call them straight from the client. This is the one case where we recommend that, precisely because there is no key to leak.

Ready to build?

Create a free account and get your API key — 5,000 free hits a month, and two endpoints that need no key at all.