Guides

How Indian public holidays work, and how to use this API in HR and payroll systems.

Integration & Productivity6 min readUpdated Oct 2026

Syncing Indian State Holidays to Google Calendar & Outlook: Dynamic iCal Feeds

Why default Google Calendar holiday feeds miss regional Indian state holidays, and how to dynamically generate RFC 5545 iCalendar feeds using the Calendar API.

1. The Missing Link in Google Calendar

Google Calendar provides a pre-packaged public holiday calendar for India (en.indian#holiday@group.v.calendar.google.com). While convenient, it exhibits severe operational limitations for distributed engineering teams:

  • It bundles central holidays and broad religious festivals, but completely omits state-specific gazetted holidays.
  • An employee in Bengaluru does not see Kannada Rajyotsava (Nov 1) or Ugadi.
  • An employee in Mumbai does not see Maharashtra Day (May 1) or Ganesh Chaturthi.
  • Teams relying on Google Calendar for project sprint planning, release freezes, or on-call rotations suffer scheduling conflicts due to untracked regional days off.

2. The iCalendar (RFC 5545) Standard

Modern calendar clients (Google Calendar, Apple Calendar, Microsoft Outlook, Thunderbird) support subscribing to web-hosted .ics calendar feeds via WebCal / HTTP.

An RFC 5545 compliant feed requires:

  • BEGIN:VCALENDAR and VERSION:2.0 headers.
  • Distinct VEVENT blocks for every holiday event.
  • Deterministic UID generation (e.g. uid-${year}-${region}-${holiday_id}@calendar-api.org) so calendar clients update existing events rather than duplicating them.
  • All-day event timestamps using VALUE=DATE:YYYYMMDD.

3. Generating Dynamic iCal Feeds from the Calendar API

By querying the Calendar API's /v1/holidays endpoint, you can serialize regional payloads into an on-demand .ics stream:

``bash # Fetch state holidays for Karnataka (KA) for year 2026 curl -s "https://calendar-api-d7a8.onrender.com/v1/holidays?country=IN&region=KA&year=2026" ``

Each returned record contains the exact date, holiday name, and administrative classification (gazetted_holiday vs restricted_holiday).

4. Live iCal Feed Server (Node.js Edge Endpoint)

Here is an Express/Node.js endpoint that pipes state-filtered Indian holidays directly into Google Calendar or Apple Calendar:

Code Reference
import express from 'express';
import fetch from 'node-fetch';

const app = express();

app.get('/feeds/:region.ics', async (req, res) => {
  const { region } = req.params;
  const year = new Date().getFullYear();

  const apiUrl = `https://calendar-api-d7a8.onrender.com/v1/holidays?country=IN&region=${region.toUpperCase()}&year=${year}`;
  const response = await fetch(apiUrl);
  const payload = await response.json();

  if (!payload.success) {
    return res.status(404).send('Region or year holiday data not found');
  }

  let ics = [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//India Calendar API//NONSGML Regional Holidays//EN',
    `X-WR-CALNAME:India Holidays (${region.toUpperCase()})`,
    'X-WR-TIMEZONE:Asia/Kolkata',
    'CALSCALE:GREGORIAN'
  ];

  for (const h of payload.data) {
    const compactDate = h.date.replace(/-/g, '');
    const uid = `${compactDate}-${region}-${h.name.replace(/\s+/g, '-').toLowerCase()}@calendar-api`;
    ics.push(
      'BEGIN:VEVENT',
      `UID:${uid}`,
      `DTSTAMP:${compactDate}T000000Z`,
      `DTSTART;VALUE=DATE:${compactDate}`,
      `SUMMARY:${h.name} (${h.type === 'gazetted_holiday' ? 'Gazetted' : 'Restricted'})`,
      `DESCRIPTION:${h.description || 'Public holiday in ' + region}`,
      'STATUS:CONFIRMED',
      'TRANSP:TRANSPARENT',
      'END:VEVENT'
    );
  }

  ics.push('END:VCALENDAR');

  res.setHeader('Content-Type', 'text/calendar; charset=utf-8');
  res.setHeader('Content-Disposition', `attachment; filename="holidays-${region}.ics"`);
  res.send(ics.join('\r\n'));
});

app.listen(3000, () => console.log('iCal feed generator active on port 3000'));