Skip to main content

First Content API Call

Use this page to verify that your token retrieval and header injection are working correctly.

What this page covers

The required request headers, the first GET /content/api/v4/chapters call, a backend proxy pattern, and a simple success check.

Required Headers​

Every authenticated Content API request must include both headers:

x-auth-token: YOUR_ACCESS_TOKEN
x-client-id: YOUR_CLIENT_ID

First Request: List Chapters​

Use the chapters endpoint as your first verification call:

curl --request GET \
--url https://apis-prelive.quran.foundation/content/api/v4/chapters \
--header "x-auth-token: YOUR_ACCESS_TOKEN" \
--header "x-client-id: YOUR_CLIENT_ID"
Expand for Python and Node.js request examples

Python Example (requests)​

import os

import requests

API_BASE_BY_ENV = {
"production": "https://apis.quran.foundation",
"prelive": "https://apis-prelive.quran.foundation",
}
env = os.getenv("QF_ENV", "prelive")
if env not in API_BASE_BY_ENV:
raise ValueError(
f"Invalid QF_ENV value: {env!r}. Expected 'prelive' or 'production'."
)

API_BASE_URL = API_BASE_BY_ENV[env]
access_token = "YOUR_ACCESS_TOKEN" # Replace with your token helper or prior manual-auth step.

response = requests.get(
f"{API_BASE_URL}/content/api/v4/chapters",
headers={
"x-auth-token": access_token,
"x-client-id": os.environ["QF_CLIENT_ID"],
},
timeout=30,
)
response.raise_for_status()

data = response.json()
print(data["chapters"][0]["name_simple"])

This example uses YOUR_ACCESS_TOKEN as a placeholder. In production, reuse your token helper or cache from the manual authentication step instead of exporting one-off token environment variables.

Node.js Example (fetch)​

This example assumes Node 18+ or another runtime with a global fetch implementation.

async function listChapters() {
const apiBaseByEnv = {
production: "https://apis.quran.foundation",
prelive: "https://apis-prelive.quran.foundation",
};
const env = process.env.QF_ENV ?? "prelive";
if (!(env in apiBaseByEnv)) {
throw new Error("QF_ENV must be 'prelive' or 'production'");
}

const apiBaseUrl = apiBaseByEnv[env];

const response = await fetch(`${apiBaseUrl}/content/api/v4/chapters`, {
headers: {
"x-auth-token": "YOUR_ACCESS_TOKEN",
"x-client-id": process.env.QF_CLIENT_ID,
},
});

if (!response.ok) {
throw new Error(`Chapters request failed: ${response.status}`);
}

const data = await response.json();
console.log(data.chapters[0].name_simple);
}

Example Successful Response​

{
"chapters": [
{
"id": 1,
"name_simple": "Al-Fatihah",
"verses_count": 7
}
]
}

Handle Errors​

Check the HTTP status before trusting the response body. Content API error responses usually include a JSON body with message, type, and success: false; endpoint reference pages show the exact response shapes.

StatusWhat it usually meansWhat to do
400 or 422Missing headers, invalid query parameters, or validation failureFix the request before retrying.
401The access token is missing, expired, or invalidClear the cached token, request a new Client Credentials token, and retry once.
403Wrong client, wrong environment, or missing content scope/permissionConfirm x-client-id, token environment, and scope=content. Do not retry in a loop.
429Rate limit exceededBack off and retry later. Prefer exponential backoff with jitter.
500, 502, 503, 504Temporary server or upstream failureRetry with bounded backoff, then surface a temporary failure.

Client Credentials does not use a refresh_token. When a Content API token expires, re-request a new token from /oauth2/token. See token management for the full cache and retry-once pattern.

Backend Proxy Pattern​

Prefer exposing a backend route instead of letting the browser call the Content APIs directly.

app.get("/chapters", async (req, res) => {
try {
const data = await callQfApi("/content/api/v4/chapters");
res.json(data);
} catch (error) {
res.status(500).json({ error: "Failed to fetch chapters" });
}
});

Your frontend can then call your backend route without handling tokens:

const response = await fetch("/chapters");
const data = await response.json();

AI Handoff Prompt​

Use this prompt when you want an AI coding tool to wire up the first authenticated Content API request:

Expand AI handoff prompt
Implement the first authenticated Quran Foundation Content API call on the backend.

Requirements
- Call GET /content/api/v4/chapters against the correct prelive or production base URL.
- Send both required headers: x-auth-token and x-client-id.
- Reuse the existing backend token helper instead of requesting a new token for every request.
- Handle non-2xx responses safely:
- 401: clear cached token, re-request a Client Credentials token, and retry once.
- 403: check client credentials, environment, and scope=content.
- 429 and 5xx: retry only with bounded backoff.
- 400/422: surface a request validation error instead of retrying blindly.
- Expose a backend route or service method that returns the chapters response without leaking credentials to the frontend.
- Verify success by checking that the response contains a chapters array.

Documentation to follow
- First API call: https://api-docs.quran.foundation/docs/quickstart/first-api-call
- Token management: https://api-docs.quran.foundation/docs/quickstart/token-management
- Content API reference: https://api-docs.quran.foundation/docs/category/content-apis

Verification Checklist​

  • The request returns JSON with a chapters array.
  • Your backend sent both x-auth-token and x-client-id.
  • No tokens or secrets appear in logs.
  • If the token had expired, your client re-requested it once and retried once.

Continue​