Resources API
from quran_foundation import ChapterRecitationSnapshotRecord, QuranClient
client = QuranClient(client_id="YOUR_CLIENT_ID", access_token="APP_ACCESS_TOKEN")
translations = client.list_translations()
translation_info = client.get_translation_info(131)
recitations = client.list_recitations()
snapshot = client.get_resource_snapshot("translations", 131)
mushaf_snapshot = client.get_mushaf_snapshot(1)
core_snapshot = client.get_quran_core_snapshot()
chapter_snapshot = client.get_chapter_recitation_snapshot(159)
chapter_records: list[ChapterRecitationSnapshotRecord] = chapter_snapshot["records"]
for record in chapter_records:
if record["record_type"] == "audio_segment":
print(record["verse_key"], record["segments"])
transliteration_snapshot = client.get_word_by_word_transliteration_snapshot(60)
Supported helpers:
list_recitations(params=None)get_recitation_info(recitation_id, params=None)list_translations(params=None)get_translation_info(translation_id, params=None)list_tafsirs(params=None)get_tafsir_info(tafsir_id, params=None)list_languages(params=None)list_chapter_infos(params=None)list_chapter_reciters(params=None)list_recitation_styles(params=None)list_verse_media(params=None)sync_resources(params=None)get_resource_snapshot(resource_group, resource_id, params=None)get_chapter_recitation_snapshot(audio_recitation_id, params=None)get_word_by_word_translation_snapshot(word_by_word_translation_id, params=None)get_word_by_word_transliteration_snapshot(word_by_word_transliteration_id, params=None)get_mushaf_snapshot(mushaf_id, params=None)get_quran_core_snapshot(params=None)(singletonquran_core:1)
Use mushafs:<id> in sync_resources(...), then call
get_mushaf_snapshot(...) to download metadata, page mappings, positioned
words, and layout data. Font files and Mushaf images are not included. See the
Font Rendering guide for implementation
details and the Developer Terms for caching and bundling conditions.
Use chapter_recitations:<id> to sync chapter audio, where <id> is an
Audio::Recitation.id, then call get_chapter_recitation_snapshot(id).
The returned records are chapter_audio_file rows and associated
audio_segment verse and word timings. The SDK exports
ChapterAudioFileSnapshotRecord, AudioSegmentSnapshotRecord, and the
ChapterRecitationSnapshotRecord union. This is distinct from the legacy
recitations:<id> group, which is keyed by an ayah-recitation ID and may include
compatible chapter audio and timing rows for existing clients. Segment
timestamps and tuple boundaries are milliseconds from the start of the chapter
file; each tuple is [one_based_word_index, start_ms, end_ms]. Use
duration_ms for exact arithmetic; duration is the legacy whole-seconds
compatibility value.
Bootstrap returns RESOURCE_CREATE entries with snapshot_url; it does not
return timing rows inline. Fetch and apply every referenced snapshot, including
the audio_segment rows, before storing the final sync token. For incremental
audio_segment ROW_CREATE, ROW_UPDATE, and ROW_DELETE mutations, use
(resource_group, resource_id, record_type, record_key) as the stable local
key. Do not depend on source_record_id or data, because either may be None
for a delete. When RESOURCE_INVALIDATE is returned, replace the complete
chapter-recitation snapshot.
Canonical Quran Core
quran_core:1 provides canonical Uthmani verse text, word-level IndoPak and
Uthmani Tajweed text, Surah metadata, and Juz/Hizb/Rub-el-Hizb boundaries. The
SDK exports QuranCoreSnapshotRecord and typed chapter, verse, word, and
boundary variants, including QuranCoreWordSnapshotRecord. Its
resource_content_id is None; local rows use (record_type, id) as their
key. Mushaf-specific page/line/glyph data remains in mushafs:<id>.
changes = client.sync_resources(params={
"bootstrap": True,
"resources": "mushafs:1;quran_core:1",
})
core = client.get_quran_core_snapshot()
for record in core["records"]:
if record["record_type"] == "verse":
print(record["verse_key"], record["text_uthmani"])
if record["record_type"] == "word":
print(
record["location"],
record.get("text_indopak_nastaleeq"),
record["text_uthmani_tajweed"],
)
Use text_indopak_nastaleeq for IndoPak text and render it with the compatible
IndoPak Nastaleeq font;
text_indopak is deprecated and retained for compatibility. Existing local
copies receive the new field after the resource is re-snapshotted or
backfilled, so read it with .get() until then.
Use the same combined filter for incremental sync, and replace the complete
resource on RESOURCE_INVALIDATE.
Word-by-Word Transliterations
Use the resource content ID with word_by_word_transliterations. This group is
separate from the translation-only word_by_word_translations group and
contains approved, shareable, one-word transliteration resources.
changes = client.sync_resources(
params={
"bootstrap": True,
"resources": "word_by_word_transliterations:60",
}
)
snapshot = client.get_word_by_word_transliteration_snapshot(60)
for record in snapshot["records"]:
print(record["word_id"], record["text"])
Each word_transliteration snapshot record has exactly these fields:
id, resource_content_id, resource_id, word_id, language_id,
language_name, text, and updated_at. Snapshots are ordered by word_id,
then id. resource_id == resource_content_id == ResourceContent.id identifies
the owning resource, while word_id identifies the normalized Word owner.
Production resource 60 currently contains 77,429 records; row id: 1 has
normalized word_id: 1 and text "bis'mi". Incremental row mutations use
record_type="word_transliteration".
Read next: