KitabHub API
Build with Books
Integrate reading data, book metadata, and literary social features into your app. One API. Bilingual. Built for the Arab world and beyond.
Quick Start
All API requests require an API key passed in the Authorization header. Generate a key in the My API Keys section below.
curl -H "Authorization: Bearer kb_live_..." \
"https://kitabhub.app/api/v1/books/search?q=نجيب+محفوظ"Authentication
Pass your API key in the Authorization header using the Bearer scheme:
Authorization: Bearer kb_live_<your_key>Rate Limits
| Plan | Requests / minute | Requests / day |
|---|---|---|
| Free | 60 | 2,000 |
| Premium | 300 | 50,000 |
Response Format
All responses are JSON. Successful responses return the requested resource wrapped in a top-level key (e.g. { "books": [...] }). Errors return { "error": "..." }.
Error Codes
| Status | Name | Meaning |
|---|---|---|
400 | Bad Request | Missing or invalid query parameter |
401 | Unauthorized | Missing or invalid API key |
403 | Forbidden | Resource is private |
404 | Not Found | Resource does not exist |
409 | Conflict | Duplicate resource or constraint violation |
429 | Too Many Requests | Rate limit exceeded |
500 | Server Error | Unexpected server error |
Endpoints
Books
/api/v1/books/searchSearch books by title, author, or ISBN across the KitabHub catalogue and external sources.
| Parameter | Type | Required | Description |
|---|---|---|---|
q | string | required | Search query (min 2 chars). Supports Arabic and English. |
limit | number | optional | Max results to return (1–20, default 10). |
source | string | optional | "all" | "local" | "external". Defaults to "all". |
// Response
{
"books": [
{
"id": "clx...",
"title": "أولاد حارتنا",
"author": "نجيب محفوظ",
"cover": "https://...",
"isbn": "978-977-419-975-0",
"rating": 4.6,
"ratingCount": 1840,
"genre": ["Literary Fiction", "Arabic Literature"],
"language": "ar",
"_source": "kitabhub"
}
],
"total": 1
}/api/v1/books/{id}Retrieve full metadata for a specific book by its KitabHub ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | required | Book ID (path param). |
// Response
{
"book": {
"id": "clx...",
"title": "أولاد حارتنا",
"author": "نجيب محفوظ",
"description": "...",
"cover": "https://...",
"isbn": "978-977-419-975-0",
"rating": 4.6,
"ratingCount": 1840,
"genre": ["Literary Fiction"],
"language": "ar",
"pageCount": 432,
"publisher": "دار الشروق",
"hasAudiobook": false,
"_count": { "reviews": 412, "shelfBooks": 3800 }
}
}/api/v1/books/trendingReturns up to 20 trending books based on reads, want-to-reads, reviews, and currently-reading activity over the past 7 days. Cached for 1 hour.
// Response
{
"books": [
{
"id": "clx...",
"title": "...",
"author": "...",
"cover": "https://...",
"rating": 4.3,
"genre": ["..."],
"trendingScore": 248
}
]
}Users (Public Profiles)
/api/v1/users/{handle}Retrieve the public profile of a KitabHub user by their handle. Private accounts return only minimal info.
| Parameter | Type | Required | Description |
|---|---|---|---|
handle | string | required | The user's @handle (without the @). |
// Response
{
"user": {
"id": "clx...",
"handle": "naguib_m",
"name": "نجيب محفوظ",
"bio": "Nobel Prize laureate...",
"image": "https://...",
"isVerifiedAuthor": true,
"genres": ["Literary Fiction", "Arabic Literature"],
"_count": { "followers": 14200, "following": 3, "bookReviews": 0 }
}
}/api/v1/users/{handle}/shelfReturns the public bookshelf of a user. Returns 403 if the user has set their shelves to private.
| Parameter | Type | Required | Description |
|---|---|---|---|
handle | string | required | User handle. |
shelf | string | optional | Filter to a specific shelf: "Read" | "Currently Reading" | "Want to Read". |
limit | number | optional | Max books per shelf (1–50, default 20). |
cursor | string | optional | Pagination cursor from previous response. |
Clubs
/api/v1/clubsList all public reading clubs. Supports search and genre filtering.
| Parameter | Type | Required | Description |
|---|---|---|---|
search | string | optional | Search clubs by name or description. |
genre | string | optional | Filter by genre tag. |
page | number | optional | Page number (default 1). |
limit | number | optional | Results per page (1–50, default 20). |
/api/v1/clubs/{id}Retrieve details of a specific public reading club.
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | required | Club ID (path param). |
Code Examples
curl
curl -H "Authorization: Bearer kb_live_..." \
"https://kitabhub.app/api/v1/books/search?q=نجيب+محفوظ"JavaScript / TypeScript
const response = await fetch(
"https://kitabhub.app/api/v1/books/search?q=Naguib+Mahfouz",
{ headers: { "Authorization": "Bearer kb_live_..." } }
);
const { books } = await response.json();
console.log(books[0].title); // "Children of the Alley"Python
import requests
resp = requests.get(
"https://kitabhub.app/api/v1/books/search",
params={"q": "Naguib Mahfouz"},
headers={"Authorization": "Bearer kb_live_..."},
)
books = resp.json()["books"]
print(books[0]["title"]) # Children of the AlleyRSS & Atom Feeds
KitabHub exposes standard syndication feeds so any RSS reader or aggregator can track a user's reading activity or a book club's updates — no API key required. Feeds are cached for 30 minutes and only available for public profiles.
Profile feeds
/api/rss/{handle}RSS 2.0/api/atom/{handle}Atom 1.0Returns up to 50 recent reading events for a public user profile — books added to the Read shelf, currently-reading starts, published reviews, and reading milestones. Both feeds carry the same content; choose the format your toolchain prefers.
<!-- Auto-discovered by browsers & readers from the profile <head> -->
<link rel="alternate" type="application/rss+xml"
title="@naguib_m on KitabHub"
href="https://kitabhub.app/api/rss/naguib_m" />
<link rel="alternate" type="application/atom+xml"
title="@naguib_m on KitabHub"
href="https://kitabhub.app/api/atom/naguib_m" />Book club feed
/api/rss/club/{id}RSS 2.0Returns recent activity for a public book club: new members, finished books (with average member ratings), new discussions, and upcoming meetings.
| Feed item type | Example title |
|---|---|
| New member | Sara Al-Rashid joined Fiction Fridays |
| Finished book | Fiction Fridays finished reading “Frankenstein in Baghdad” |
| New discussion | New discussion about “The Alchemist” in Fiction Fridays |
| Upcoming meeting | Upcoming meeting: October Wrap-Up — Fiction Fridays |
Webhooks
Webhooks let you receive real-time HTTP POST notifications when activity happens on a KitabHub account. Your endpoint must be HTTPS. Managing webhooks requires a valid API key (see My API Keys).
Available events
| Event | Fired when | Payload fields |
|---|---|---|
shelf.add | A book is added to any shelf | bookId, bookTitle, shelf, shelfBookId |
review.create | A new book review is published | bookId, rating, reviewId |
goal.complete | A reading goal target is reached | year, target, booksRead, goalId |
Managing webhooks
/api/developer/webhooksList webhooks/api/developer/webhooksCreate webhook (returns secret once)/api/developer/webhooks?id=Delete a webhook// Create a webhook
const res = await fetch("https://kitabhub.app/api/developer/webhooks", {
method: "POST",
headers: {
"Authorization": "Bearer kb_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://your-app.com/hooks/kitabhub",
events: ["shelf.add", "review.create"],
}),
});
const { webhook, signingSecret } = await res.json();
// signingSecret is shown ONCE — store it securelyVerifying webhook signatures
Every request includes an X-KitabHub-Signature header containing an HMAC-SHA256 signature of the raw request body, prefixed with sha256=. Always verify this before trusting the payload.
JavaScript / Node.js
import crypto from "crypto";
export function verifyKitabHubSignature(
body: string, // raw request body (string, not parsed)
signature: string, // X-KitabHub-Signature header value
secret: string, // your signing secret
): boolean {
const expected = "sha256=" +
crypto.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}Python
import hmac
import hashlib
def verify_kitabhub_signature(
body: bytes, # raw request body bytes
signature: str, # X-KitabHub-Signature header
secret: str,
) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)The X-KitabHub-Event header also identifies the event type (e.g. shelf.add) so you can route quickly without parsing the body first.
My API Keys
Sign in to generate API keys
Create a free KitabHub account to get your personal API key and start building.
Support
Help & Documentation
Questions about the API? Visit our help center or contact us directly.
Help Center →