REST API for building mobile apps, integrations, and custom frontends on SetiaPoints. All responses are JSON.
The API uses two layers of authentication:
1. API Key (app-level) — Required for all endpoints except /shop and /auth. Pass via the X-API-Key header. Generate keys in your admin Settings page.
2. Bearer Token (user-level) — Required for user-specific endpoints. Obtained by calling /auth or /auth/staff. JWT with 7-day expiry. Pass via Authorization: Bearer {token} header.
// Example: both headers on a protected request
X-API-Key: sp_a1b2c3d4e5f6...
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...
Authenticate a customer by phone number. Auto-registers if the number is new.
| Parameter | Type | Description |
|---|---|---|
phone required | string | Phone number, e.g. "0179064733" |
// Request POST /api/bosscafe/auth Content-Type: application/json { "phone": "0179064733" } // Response { "error": false, "message": "Login successful", "token": "eyJhbGciOiJIUzI1NiJ9...", "user": { "id": 3, "name": "0179064733", "phone": "0179064733", "role": "customer" } }
| Parameter | Type | Description |
|---|---|---|
email required | string | Staff email |
password required | string | Staff password |
// Request POST /api/bosscafe/auth/staff Content-Type: application/json { "email": "[email protected]", "password": "staff123" } // Response — same format as customer auth
No authentication required.
// Response { "error": false, "shop": { "id": 1, "name": "BossCafe", "slug": "bosscafe", "logo": null, "brand_color": "#FF6B9D", "reward_threshold": 10 } }
// Headers Authorization: Bearer {token} // Response { "stamps": 7, "threshold": 10, "progress": 70.0, "rewards_available": 0, "stamps_to_next_reward": 3 }
| Query Param | Type | Description |
|---|---|---|
limit | int | Max results (default 20, max 100) |
offset | int | Pagination offset (default 0) |
// Response { "history": [ { "type": "stamp", "value": 1, "notes": "Coffee", "created_at": "2026-04-01 14:30:00" }, { "type": "reward", "value": 10, "notes": "Free item", "created_at": "2026-03-20 11:00:00" } ] }
| Query Param | Type | Description |
|---|---|---|
q required | string | Search by phone or name (min 2 chars) |
// Response { "results": [ { "id": 3, "name": "0179064733", "phone": "0179064733", "stamps": 7, "can_stamp": true, "can_redeem": false } ] }
| Parameter | Type | Description |
|---|---|---|
customer_id required | int | Customer user ID |
notes | string | Purchase note (optional) |
// Request POST /api/bosscafe/staff/stamp Authorization: Bearer {token} Content-Type: application/json { "customer_id": 3, "notes": "Double espresso" } // Response { "stamp_id": 15, "new_stamp_count": 8, "can_redeem": false }
Returns 429 if cooldown is active (5 min between stamps to same customer).
| Parameter | Type | Description |
|---|---|---|
customer_id required | int | Customer user ID |
reward_description | string | Reward name (default: "Free item") |
// Response { "redemption_id": 5, "new_stamp_count": 0, "reward": "Free coffee" }
| Query Param | Type | Description |
|---|---|---|
limit | int | Max results (default 10, max 50) |
// Response { "stats": { "total_customers": 150, "total_stamps": 843, "total_redemptions": 27, "total_staff": 3 } }
| Query Param | Type | Description |
|---|---|---|
limit | int | Max results (default 50, max 200) |
offset | int | Pagination offset |
GET to list, POST to add a new staff member.
| Parameter | Type | Description |
|---|---|---|
name required | string | Staff name |
email required | string | Staff email |
password required | string | Password (min 6 chars) |
| Query Param | Type | Description |
|---|---|---|
limit | int | Max results (default 50, max 200) |
offset | int | Pagination offset |
All errors return a consistent JSON format:
{
"error": true,
"message": "Description of what went wrong"
}
| Status | Meaning |
|---|---|
200 | Success |
400 | Bad request — missing or invalid parameters |
401 | Unauthorized — missing or invalid token |
403 | Forbidden — insufficient role or shop mismatch |
404 | Not found — shop, customer, or endpoint not found |
405 | Method not allowed — wrong HTTP method |
429 | Rate limited — stamp cooldown active |