Getting Started with Content Sync
Content Sync helps an app keep a local copy of public Quran.Foundation content fresh. Instead of downloading every translation, tafsir, recitation, or article again, your app asks:
- What changed since the last time I checked?
- Which small rows can I update directly?
- Which full content copy do I need to download again?
Terms
| Term | Plain meaning |
|---|---|
| Resource | One content item your app tracks, such as translation 19, tafsir 151, recitation 10, or article 123. |
| Resource filter | The list of content your app wants to keep in sync, for example translations:19;tafsirs:151. |
| Change | One server event telling your app what changed. The API field is called type. |
| Full copy | The complete current rows for one resource. The API calls this a snapshot. |
| Snapshot URL | A relative API path returned on some changes. Fetch it to replace the full local copy for that one resource. |
| Sync token | A private checkpoint returned by the API. Store it and send it next time to get only newer changes. |
| Sync sequence | A server sequence number for content changes. Mutations expose this as sequence. |
| Sync until | The upper sequence bound for one sync run. The API field is called sync_until_sequence. |
| Cursor | A temporary page link. Use it only while finishing the current sync request. |
When next_page_url or snapshot_url is present and non-null, we return a relative /api/v4/... path, such as /api/v4/resources/sync?cursor=... or /api/v4/resources/snapshots/translations/19. You should prefix that path with https://apis.quran.foundation/content.
Supported Content
Content Sync currently supports these resource groups: translations, tafsirs, recitations, and articles.
| Resource group | What the full copy contains | Changes included |
|---|---|---|
translations | Translation rows for the resource. Footnotes are nested inside each translation row. | Translation row changes and footnote-driven translation row updates. |
tafsirs | Tafsir rows for the resource. | Tafsir row changes. |
recitations | Ayah audio files and chapter audio files for the recitation. | Ayah audio file and chapter audio file changes. |
articles | Visible article localizations. | Article localization changes and resource-level refresh, delete, or restore events. |
If a resource group is not listed above, it is not accepted by this sync endpoint. Continue using that resource's regular API endpoint when available.
First Sync
On first sync, ask for the content you want and set bootstrap=true. The API returns pages of RESOURCE_CREATE changes. Each one includes a snapshot_url, which points to the full copy for that resource.
curl "https://apis.quran.foundation/content/api/v4/resources/sync?bootstrap=true&resources=translations:19;tafsirs:151&per_page=100" \
-H "x-auth-token: $ACCESS_TOKEN" \
-H "x-client-id: $CLIENT_ID"
If has_more is true, call next_page_url until it becomes false. Store next_sync_token only from the final page.
Fetch and apply any returned snapshot_url values before you mark the sync as complete locally.
Fetching a Full Copy
A full copy returns all current rows for one resource. For example, a translation full copy returns the current translation rows for that translation resource.
curl "https://apis.quran.foundation/content/api/v4/resources/snapshots/translations/19" \
-H "x-auth-token: $ACCESS_TOKEN" \
-H "x-client-id: $CLIENT_ID"
Client rule: replace all local rows for translations:19 with the records array from the response.
How Snapshots Relate to Tokens
The sync_token is not sent to the snapshot endpoint. The token belongs to GET /resources/sync only.
During bootstrap, the link between sync and snapshots is the RESOURCE_CREATE mutation:
GET /resources/sync?bootstrap=true...returnsRESOURCE_CREATEchanges.- Each
RESOURCE_CREATEincludes asnapshot_url. - Your app fetches each
snapshot_urland replaces local rows for that resource. - Your app stores the final
next_sync_tokenafter all returned changes have been applied. - Later, your app sends that token back to
GET /resources/syncwith the same canonicalresourcesfilter.
Snapshots are current when fetched. They are not pinned to the exact sequence of the change that asked you to fetch them.
Next Sync
After first sync, use the stored sync_token with the same resources filter. The API returns only newer changes.
curl "https://apis.quran.foundation/content/api/v4/resources/sync?sync_token=$SYNC_TOKEN&resources=translations:19;tafsirs:151&per_page=100" \
-H "x-auth-token: $ACCESS_TOKEN" \
-H "x-client-id: $CLIENT_ID"
Sequence Fields
sequence on a mutation is the server's increasing content-change number for that mutation. Apply mutations in ascending sequence order.
sync_until_sequence on a sync response is the upper bound fixed for that sync run. If the response has more pages, every next_page_url continues the same run with the same upper bound. This keeps pagination stable even if newer content changes are committed while your app is paging.
sync_sequence on a snapshot response is the current server sequence when the snapshot was fetched. Do not use snapshot sync_sequence as your next checkpoint. Only store next_sync_token from the final sync page.
Mutation Types
| Type | Client action |
|---|---|
RESOURCE_CREATE | Fetch snapshot_url, then replace all local rows for that resource. |
RESOURCE_INVALIDATE | Fetch snapshot_url, then replace all local rows for that resource. |
RESOURCE_DELETE | Remove or hide the full local resource. |
RESOURCE_UPDATE | Keep existing rows. Treat it as a resource-level freshness marker. |
ROW_CREATE | Upsert one local row using resource_group, resource_id, record_type, and record_key. |
ROW_UPDATE | Upsert one local row using resource_group, resource_id, record_type, and record_key. |
ROW_DELETE | Delete one local row using resource_group, resource_id, record_type, and record_key. |
Only RESOURCE_CREATE and RESOURCE_INVALIDATE include snapshot_url.
Testing Sync Behavior
You can test bootstrap and snapshot fetches with real public resources. To test pagination, use a resources filter that returns more items than per_page. To observe a no-change incremental sync, call sync again with the final next_sync_token when no matching content changes have occurred.
Mutation scenarios such as row updates, deletes, resource deletes, restores, and invalidations require actual content changes on tracked resources. The public API does not expose a way to force those events on demand.