JavaScript Client Library (CDN SDK)
Browser-first JavaScript client for the Orthodox Calendar API.
CDN usage
<script src="https://api.ispovednik.org/cdn/orthodox-calendar-api.min.js"></script>
<script type="module">
const client = OrthodoxCalendarApi.createClient({
baseUrl: 'https://api.ispovednik.org/api/v1',
defaultLang: 'ru',
});
async function run() {
const res = await client.calendar.day('2027-06-19');
console.log(res.data['2027-06-19']);
}
run().catch(console.error);
</script>
Construction
type Lang = 'ru' | 'en' | 'cu'; // 'cu' (Church Slavonic) applies to the canons/akathists content endpoints
type ClientOptions = {
baseUrl?: string; // default: https://api.ispovednik.org/api/v1
defaultLang?: Lang; // default: 'ru'
defaultType?: number; // optional default saints type filter
timeoutMs?: number; // default: 15000
fetchImpl?: typeof fetch; // override for tests / SSR
onRequest?: (ctx: { url: string; init: RequestInit }) => void;
onResponse?: (ctx: { url: string; status: number }) => void;
normalize?: boolean; // default: false (see “Normalization”)
dedupe?: boolean; // default: true (in-flight request memoization)
cacheTtlMs?: number; // default: 0 (disabled)
maxCacheEntries?: number; // default: 200
};
client = OrthodoxCalendarApi.createClient(options);
All endpoint methods accept:
type RequestOptions = {
lang?: Lang;
type?: number; // only where API supports it
signal?: AbortSignal;
timeoutMs?: number;
raw?: boolean; // bypass normalization (if enabled)
};
Endpoint coverage (v1)
client.calendar.day(date, opts)→GET /calendar/day/{YYYY-MM-DD}client.calendar.month(year, month, opts)→GET /calendar/month/{YYYY}/{M}client.calendar.year(year, opts)→GET /calendar/year/{YYYY}client.calendar.range(from, to, opts)→GET /calendar/range?from=...&to=...client.calendar.rangeChunked(from, to, opts)→ splits/merges range calls (max 366 days per request)
Calendar day objects include weekAfterPentecost as an always-present numeric field.
Calendar and saints response saint entries include liturgicalRank. The value is either null when the rank is not confirmed, or an object with code, group, and localized label. Use this field for feast sign and order-of-service rank data; type / typeId remain legacy filtering classifications.
client.saints.day(date, opts)→GET /saints/day/{YYYY-MM-DD}client.saints.month(year, month, opts)→GET /saints/month/{YYYY}/{M}client.saints.year(year, opts)→GET /saints/year/{YYYY}client.saints.range(from, to, opts)→GET /saints/range?from=...&to=...client.saints.rangeChunked(from, to, opts)client.fasting.day(date, opts)→GET /fasting/day/{YYYY-MM-DD}client.fasting.month(year, month, opts)→GET /fasting/month/{YYYY}/{M}client.fasting.year(year, opts)→GET /fasting/year/{YYYY}client.fasting.range(from, to, opts)→GET /fasting/range?from=...&to=...client.fasting.rangeChunked(from, to, opts)client.movable.day(date, opts)→GET /movable/day/{YYYY-MM-DD}client.movable.year(year, opts)→GET /movable/year/{YYYY}client.movable.range(fromYear, toYear, opts)→GET /movable/range?from=YYYY&to=YYYYclient.movable.rangeChunked(fromYear, toYear, opts)→ splits/merges range calls (max 100 years per request)client.memorial.year(year, opts)→GET /memorial/year/{YYYY}client.hymnography(id, opts)→GET /hymnography?id=...— content endpoint;opts.langacceptsru|en(defaultru). Returns troparia, kontakia, prayers, magnifications, hagiography, and icons.client.canons(id, opts)→GET /canons?id=...— content endpoint;opts.langacceptsru|cu|en(defaultru),opts.numberfilters to a single canon by its publicnumber.client.akathists(id, opts)→GET /akathists?id=...— content endpoint;opts.langacceptsru|cu|en(defaultru),opts.numberfilters to a single akathist by its publicnumber.
Content endpoints return a found/notFound envelope per id (HymnographyEnvelope / CanonsEnvelope / AkathistsEnvelope). canons/akathists take ContentRequestOptions ({ lang?, number?, signal?, timeoutMs? }); hymnography takes HymnographyRequestOptions ({ lang?, signal?, timeoutMs? }, lang is ru|en). A documented language with no data returns found: false; unknown lang values normalize to ru.
Errors
SDK throws ApiError:
status(HTTP status, or0for network/timeout errors)urlmessage(servererror.messagewhen available)details(servererror.detailswhen available)code(servererror.codewhen available)
Normalization
By default, SDK returns responses as-is (“raw”).
If you enable normalize: true, /saints/* responses are converted to camelCase:
gregorian_date→gregorianDateday_of_week→dayOfWeekjulian_day+julian_month→julianDay+julianMonth
You can also call helpers directly:
const raw = await client.saints.day('2026-01-01', { raw: true });
const normalized = OrthodoxCalendarApi.normalizeSaintsEnvelope(raw);
Convenience helpers
OrthodoxCalendarApi.unwrapDay(envelope)→ returns the first day object fromenvelope.dataOrthodoxCalendarApi.unwrapDataMap(envelope)→ returnsenvelope.dataclient.filterEvents(events, { kind })client.getWeekEvents(day)/client.getFeastEvents(day)/client.getCalendarEvents(day)/client.getEventEvents(day)(alias) /client.getSaintEvents(day)/client.getIconOfMotherOfGodEvents(day)client.filterSaints(day, { typeId })
CalendarEvent.kind supports: feast, event, saint, icon_of_mother_of_god, memorial, week.
Saint.liturgicalRank is always present on calendar and saints responses, with null for unknown ranks.
CalendarEvent.icons is now typed as optional IconApiItem[] for id-backed feast / event / saint / icon_of_mother_of_god entries. This is especially relevant for /movable/*, where week and memorial stay iconless.
The SDK also exports IconApiItem, IconText, IconTextBlock, and LiturgicalRank.