Resources API
Purpose: Read content metadata such as translations, tafsirs, recitations, and languages.
Use this when: You have a backend and need Content API resource data.
Do not use this when: You only have frontend or mobile code with no backend.
Backend required: Yes.
Allowed runtimes: Node.js, serverless functions, workers.
Required credentials: client_id, client_secret, Content API access.
Minimal import: @quranjs/api/server.
Use @quranjs/api/server.
import { createServerClient } from "@quranjs/api/server";
const client = createServerClient({
clientId: process.env.QF_CLIENT_ID!,
clientSecret: process.env.QF_CLIENT_SECRET!,
});
const translations = await client.content.v4.resources.translations.list();
const tafsirs = await client.content.v4.resources.tafsirs.list();
const languages = await client.content.v4.resources.languages.list();
const chapterInfoResources =
await client.content.v4.resources.chapterInfos.list();
Use chapterInfos.list() as the global chapter-info resource catalog. For chapter-specific resource availability, prefer client.content.v4.chapters.getInfoResponse(chapterId, { includeResources: true }).
Resource Catalog Helpers
The server SDK exposes typed helpers for the public Content API resource catalogs.
const recitations = await client.content.v4.resources.recitations.list();
const recitationInfo =
await client.content.v4.resources.recitations.getInfo("7");
const translations = await client.content.v4.resources.translations.list();
const translationInfo =
await client.content.v4.resources.translations.getInfo("131");
const tafsirs = await client.content.v4.resources.tafsirs.list();
const tafsirInfo = await client.content.v4.resources.tafsirs.getInfo("169");
const chapterReciters =
await client.content.v4.resources.chapterReciters.list();
const recitationStyles =
await client.content.v4.resources.recitationStyles.list();
const verseMedia = await client.content.v4.resources.verseMedia.list();
Content Resource Sync
Use content resource sync when your app keeps a local copy of public tafsirs, translations, recitations, or articles and needs to update it without downloading every row again.
The flow is:
- Bootstrap once with
bootstrap=trueand aresourcesfilter. - Page until
has_moreis false, then store the finalnext_sync_token. - Poll later with
sync_tokenand the sameresourcesfilter. - Apply row mutations directly.
- When a mutation has a non-null
snapshot_url, fetch the snapshot for thatresource_groupandresource_idand replace that local resource.
The resources filter uses plural group names (articles, recitations, tafsirs, translations). Use * for all public resources in a group or comma-separated IDs for specific resources, for example translations:19,20;tafsirs:14.
RESOURCE_UPDATE is only a resource-level freshness marker. It does not include snapshot_url; keep existing local rows unless row mutations, RESOURCE_INVALIDATE, or RESOURCE_DELETE later change them.
Use the Content API reference for the sync endpoints:
Common Mistake
Do not call Resources from @quranjs/api/public. Content APIs are server-side for confidential clients.