API Overview
The SabiBooks API provides programmatic access to the platform for partners and developers building integrations. All business operations available in the web app — products, sales, customers, expenses, and reports — are accessible through this REST API.
Base URL
Section titled “Base URL”All API requests are made relative to the following base URL:
https://app.sabibooks.com/api/v1/| Environment | Base URL |
|---|---|
| Production | https://app.sabibooks.com/api/v1/ |
| Local (dev) | http://localhost:8080/api/v1/ |
| Docker (full stack) | http://localhost:8880/api/v1/ |
Authentication
Section titled “Authentication”The SabiBooks API uses Bearer JWT authentication. All requests (except public endpoints) must include a valid access token in the Authorization header:
GET /api/v1/products HTTP/1.1Host: app.sabibooks.comAuthorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Content-Type: application/jsonTokens are obtained through a phone + OTP flow. See the Authentication page for the full flow with curl examples.
Response Format
Section titled “Response Format”All API responses are wrapped in the standard ApiResponse<T> envelope:
Successful Response
Section titled “Successful Response”{ "success": true, "message": "Product retrieved successfully", "data": { "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "name": "Peak Milk 400g", "sku": "PMK-400", "price": 1250.00, "quantity": 48, "category": "Provisions", "business_id": "b1c2d3e4-f5a6-7890-bcde-f12345678901", "created_at": "2026-02-20T10:30:00Z", "updated_at": "2026-02-20T10:30:00Z" }, "timestamp": "2026-02-20T14:22:08Z"}Paginated Response
Section titled “Paginated Response”{ "success": true, "message": "Products retrieved successfully", "data": { "content": [ { "id": "...", "name": "Peak Milk 400g", "price": 1250.00 }, { "id": "...", "name": "Golden Penny Spaghetti 500g", "price": 750.00 } ], "cursor": "eyJpZCI6ImE1YjZjN2Q4In0=", "has_next": true, "limit": 20 }, "timestamp": "2026-02-20T14:22:08Z"}Pagination
Section titled “Pagination”The API uses cursor-based pagination for all list endpoints. This provides consistent results even when data is being modified concurrently.
| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | — | Opaque cursor from a previous response. Omit for the first page. |
limit | integer | 20 | Number of items per page (max 100). |
Example
Section titled “Example”# First pagecurl -H "Authorization: Bearer <token>" \ "https://app.sabibooks.com/api/v1/products?limit=20"
# Next page (use cursor from previous response)curl -H "Authorization: Bearer <token>" \ "https://app.sabibooks.com/api/v1/products?cursor=eyJpZCI6ImE1YjZjN2Q4In0=&limit=20"Continue fetching pages until has_next is false.
Error Format
Section titled “Error Format”Errors follow the RFC 7807 Problem Details format:
{ "success": false, "message": "Product not found", "error": { "type": "https://api.sabibooks.com/errors/resource-not-found", "title": "Resource Not Found", "status": 404, "detail": "Product with ID a1b2c3d4-e5f6-7890-abcd-ef1234567890 was not found in business b1c2d3e4-f5a6-7890-bcde-f12345678901", "instance": "/api/v1/products/a1b2c3d4-e5f6-7890-abcd-ef1234567890" }, "timestamp": "2026-02-20T14:22:08Z"}Common HTTP Status Codes
Section titled “Common HTTP Status Codes”| Code | Meaning | When It Happens |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created (e.g., new product) |
400 | Bad Request | Invalid request body or parameters |
401 | Unauthorized | Missing or expired token |
403 | Forbidden | Token valid but insufficient permissions |
404 | Not Found | Resource does not exist or belongs to another business |
409 | Conflict | Duplicate resource (e.g., duplicate phone number) |
422 | Unprocessable Entity | Validation failure (e.g., negative price) |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Unexpected server error |
Key Conventions
Section titled “Key Conventions”| Aspect | Convention |
|---|---|
| Date/time | ISO 8601 format (e.g., 2026-02-20T10:30:00Z) |
| Timezone | Africa/Lagos (WAT, UTC+1) for business operations |
| Currency | NGN (Nigerian Naira), always 2 decimal places |
| Phone numbers | E.164 format (+2348012345678) |
| IDs | UUID v4 (e.g., a1b2c3d4-e5f6-7890-abcd-ef1234567890) |
| JSON fields | snake_case naming |
| Multi-tenancy | All data scoped to the authenticated user’s business |
API Module Structure
Section titled “API Module Structure”The API is organised as a modular monolith. Each business domain is a self-contained module with its own endpoints:
Directoryapi/v1/
Directoryauth/
- register
- verify-otp
- login
- refresh
- me
Directorybusinesses/
- _id_
Directorybranches/
- …
Directoryproducts/
- _id_
Directorystock-adjustments/
- …
- import
- export
Directorysales/
- _id_
- void
Directoryreceipts/
- …
Directorycustomers/
- _id_
Directorycredit/
- …
Directoryexpenses/
- _id_
Directorycategories/
- …
Directoryreports/
- daily-summary
- sales-by-category
- profit-loss
Directorystaff/
- invite
- _id_
Directorypartner/
Directorymerchants/
- …
Directoryanalytics/
- …
Directorybranding/
- …
Directoryapi-keys/
- …
Directorywebhooks/
- …