One Click Spaces API
Everything you need to build on top of Africa's bookable spaces marketplace — villas, apartments, venues and studios, all behind one REST API.
Authentication#
All API requests (except public endpoints) require a Bearer token in the Authorization header.
Authorization: Bearer <access_token>Tokens are obtained from POST /api/auth/login/. Access tokens expire in 60 minutes. Use the refresh endpoint with your refresh token to get a new one.
| Environment | Base URL |
|---|---|
| Production | https://api.oneclickspaces.com |
| Local dev | http://127.0.0.1:8000 |
Every response — success or error — uses the same envelope.
{
"success": true,
"message": "Listings retrieved successfully.",
"data": { },
"errors": null
}On error, success is false, data is null, and errors contains field-level validation errors.
| Status | Meaning |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Validation error (check errors field) |
| 401 | Missing or invalid token |
| 403 | Insufficient permissions |
| 404 | Resource not found |
| 429 | Rate limit exceeded |
| 500 | Server error |
- • Anonymous: 30 requests/minute
- • Authenticated: 200 requests/minute
- • Headers returned:
X-RateLimit-Limit,X-RateLimit-Remaining
Postman Collection#
Spin up the entire API in seconds. Import the collection and environment below into Postman, set base_url (defaults to production), then run Login — the test script auto-populates access_token and refresh_token for every subsequent request.
- 1. In Postman, click Import and drop both files.
- 2. Select the One Click Spaces — API environment in the top-right picker.
- 3. Run Authentication → Login with valid credentials.
- 4. Every authenticated request now uses the captured bearer token automatically.
/api/auth/register/Creates a new user account and sends an OTP to the provided email. If a phone number is supplied, a second OTP is sent via SMS.
Request body
{
"email": "john@example.com",
"password": "SecurePass@123",
"first_name": "John",
"last_name": "Doe",
"phone_number": "+255712345678"
}Response · 201
{
"success": true,
"message": "Registration successful. Please verify your email.",
"data": {
"user_id": "a1b2c3d4-...",
"email": "john@example.com"
},
"errors": null
}/api/auth/login/Authenticate with email and password. Returns JWT access + refresh tokens.
Request body
{
"email": "john@example.com",
"password": "SecurePass@123"
}Response · 200
{
"success": true,
"message": "Login successful.",
"data": {
"access": "<jwt_access_token>",
"refresh": "<jwt_refresh_token>",
"user": {
"id": "a1b2c3d4-...",
"email": "john@example.com",
"first_name": "John",
"role": "user",
"mode": "booking",
"verification_stage": "approved"
}
},
"errors": null
}/api/auth/logout/Blacklists the supplied refresh token.
Request body
{ "refresh": "<refresh_token>" }/api/auth/refresh/Exchange a refresh token for a new short-lived access token.
Request body
{ "refresh": "<refresh_token>" }/api/auth/verify-email/Verify the 6-digit OTP sent to the user's email.
Request body
{
"email": "john@example.com",
"otp_code": "123456"
}/api/auth/verify-phone/Verify the 6-digit OTP sent via SMS.
Request body
{
"phone_number": "+255712345678",
"otp_code": "123456"
}/api/auth/resend-otp/Resend a one-time password. purpose can be email_verification, phone_verification, or password_reset.
Request body
{
"email": "john@example.com",
"purpose": "email_verification"
}/api/auth/forgot-password/Send a password reset OTP to the user's email.
Request body
{ "email": "john@example.com" }/api/auth/reset-password/Reset password using the OTP from forgot-password.
Request body
{
"email": "john@example.com",
"otp_code": "123456",
"new_password": "NewSecurePass@123"
}Update profile#
🔒 Auth required/api/auth/update-profile/Update basic profile fields (name, phone, bio).
Request body
{
"first_name": "John",
"last_name": "Doe",
"phone_number": "+255712345678",
"bio": "Hospitality enthusiast."
}Toggle UI mode#
🔒 Auth required/api/auth/mode/Switch the user between hosting and booking experiences. Does not affect API permissions.
Request body
{ "mode": "hosting" }mode options: hosting · bookingChange password#
🔒 Auth required/api/auth/change-password/Request body
{
"old_password": "OldPass@123",
"new_password": "NewPass@123"
}Host Onboarding#
Users must complete onboarding before they can create listings. Steps are tracked server-side.
Host status#
🔒 Auth required/api/auth/host/status/Returns the host onboarding checklist.
Response · 200
{
"success": true,
"data": {
"personal_info": true,
"identity": false,
"profile_submitted": false,
"verification_stage": "not_started"
}
}Save personal info#
🔒 Auth required/api/auth/host/personal/Save name, phone, date of birth and gender.
Request body
{
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1992-03-14",
"gender": "male",
"phone_number": "+255712345678"
}Upload identity#
🔒 Auth required/api/auth/host/identity/Upload NIDA number and ID photo as multipart/form-data.
Headers
| Content-Type | multipart/form-data |
Request body
{
"nida_number": "19920314-12345-67890-12",
"id_photo": "<binary>"
}Submit profile for review#
🔒 Auth required/api/auth/host/submit/Submit the completed host profile for admin review. Sets verification_stage=pending_review.
OAuth / Providers#
Social login providers. Returns the same JWT response shape as standard login.
/api/auth/providers/google/Pass the Google ID token obtained from the frontend SDK. Creates an account on first use.
Request body
{ "id_token": "<google_id_token>" }Listings#
Browse endpoints are public. Create / edit / delete require an approved host.
/api/listings/Public. Supports the query parameters below.
| Param | Type | Description |
|---|---|---|
| category | string | Category slug (e.g. beach-villa) |
| min_price | number | Minimum price per night |
| max_price | number | Maximum price per night |
| guests | number | Minimum guest capacity |
| stay_type | string | short_stay | long_stay | both |
| check_in | date | YYYY-MM-DD |
| check_out | date | YYYY-MM-DD |
/api/listings/nearby/?lat=-6.79&lng=39.20&radius=10Public. Returns listings within radius (km) of the supplied coordinates.
Create a listing#
🔒 Host required/api/listings/Create a draft listing. Must be an approved host.
Request body
{
"title": "Luxury Beach Villa",
"property_type": "villa",
"category": "beach-villa",
"stay_type": "short_stay",
"description": "Stunning 3-bedroom beach villa with private pool.",
"address": "Msasani Peninsula, Dar es Salaam",
"city": "Dar es Salaam",
"country": "Tanzania",
"price_per_night": "350.00",
"max_guests": 6,
"bedrooms": 3,
"bathrooms": 2
}/api/listings/{listing_id}/Public. Returns full detail including photos, amenities, pricing and reviews summary.
My listings (host)#
🔒 Auth required/api/listings/host/Returns the host's own listings across all statuses.
Update basic info#
🔒 Auth required/api/listings/{listing_id}/basic-info/Update title, address, guest count, etc.
Set amenities & extras#
🔒 Auth required/api/listings/{listing_id}/amenities/Update pricing#
🔒 Auth required/api/listings/{listing_id}/pricing/Update price, cleaning fee, security deposit.
Upload photos#
🔒 Auth required/api/listings/{listing_id}/media/multipart/form-data. Uploads photos to cloud storage.
Headers
| Content-Type | multipart/form-data |
Set availability#
🔒 Auth required/api/listings/{listing_id}/availability/Set check-in / out times and blackout dates.
Submit for review#
🔒 Auth required/api/listings/{listing_id}/submit/Submit the draft listing for admin approval.
Delete listing#
🔒 Auth required/api/listings/{listing_id}/delete/Delete a draft or inactive listing.
Bookings#
Booking flow: Create Intent → Confirm → Submit Payment → Admin Confirms → Check-In → Check-Out.
Create booking intent#
🔒 Auth required/api/bookings/intents/Places a 15-minute hold on the requested dates and returns a price snapshot.
Request body
{
"listing_id": "abc-123",
"check_in_date": "2026-09-01",
"check_out_date": "2026-09-05",
"guests": 2,
"extras": []
}Response · 201
{
"success": true,
"data": {
"id": "intent-uuid",
"expires_at": "2026-06-17T12:30:00Z",
"price_snapshot": {
"nights": 4,
"price_per_night": "350.00",
"subtotal": "1400.00",
"cleaning_fee": "50.00",
"total": "1450.00"
}
}
}Confirm booking#
🔒 Auth required/api/bookings/create/Confirms the intent and creates an actual booking.
Request body
{
"intent_id": "intent-uuid",
"special_requests": "Late check-in at 6pm please."
}My bookings#
🔒 Auth required/api/bookings/Guests see their own bookings; hosts see bookings on their listings.
Submit payment proof#
🔒 Auth required/api/bookings/{booking_id}/submit-payment/Upload payment proof as multipart/form-data.
Headers
| Content-Type | multipart/form-data |
Cancel booking#
🔒 Auth required/api/bookings/{booking_id}/cancel/Cancels the booking and releases the held dates.
Check guest in#
🔒 Host/api/bookings/{booking_id}/check-in/Host action. Marks the guest as checked in.
Check guest out#
🔒 Host/api/bookings/{booking_id}/check-out/Marks the stay as complete and triggers a review prompt to the guest.
confirmed → payment_submitted → confirmed → checked_in → completedCategories#
Hierarchical property categories with nested subcategories.
/api/categories/Public. Returns the full tree with nested subcategories.
Response · 200
{
"success": true,
"data": [
{
"id": "uuid",
"name": "Villa",
"slug": "villa",
"icon": "villa",
"subcategories": [
{ "name": "Beach Villa", "slug": "beach-villa" },
{ "name": "Modern Villa", "slug": "modern-villa" }
]
}
]
}Create category#
🔒 Admin/api/categories/Update category#
🔒 Admin/api/categories/{slug}/Deactivate category#
🔒 Admin/api/categories/{slug}/Amenities & Extras#
Amenities included with a stay, plus optional paid extras.
Create amenity#
🔒 Admin/api/amenities/Update amenity#
🔒 Admin/api/amenities/{id}/Delete amenity#
🔒 Admin/api/amenities/{id}//api/amenities/extras/{id}/.Reviews#
Listing reviews include sub-ratings and host replies.
/api/reviews/listings/{listing_id}/Public. Published reviews with sub-ratings and host replies.
Submit a review#
🔒 Auth required/api/reviews/listings/{listing_id}/Submit a review for a completed booking. One review per booking.
Request body
{
"booking_id": "booking-uuid",
"rating": 5,
"cleanliness": 5,
"communication": 5,
"location": 4,
"value": 4,
"accuracy": 5,
"comment": "Absolutely stunning villa. Would book again!"
}Host reply#
🔒 Host/api/reviews/{review_id}/reply/Post a one-time reply to a review.
Request body
{ "host_reply": "Thank you so much! Come back anytime!" }Platform feedback#
🔒 Auth required/api/reviews/app/Internal platform feedback — not displayed publicly.
Request body
{
"rating": 5,
"comment": "Seamless booking experience!",
"platform": "web"
}Saved Searches#
Let users save and recall their favourite search filters.
List saved searches#
🔒 Auth required/api/filters/saved/Save a search#
🔒 Auth required/api/filters/saved/Request body
{
"name": "Dar Beach Getaway",
"category": "beach-villa",
"min_price": 100,
"max_price": 400,
"min_guests": 2,
"stay_type": "short_stay"
}Remove saved search#
🔒 Auth required/api/filters/saved/{id}/FAQ#
Help-center content grouped by category.
Admin Portal#
All /api/admin/ endpoints require role=admin or is_superuser=true.
Dashboard stats#
🔒 Admin/api/admin/stats/All listings#
🔒 Admin/api/admin/listings/?status=pending_reviewReturns listings across all statuses with optional filters.
Approve listing#
🔒 Admin/api/admin/listings/{id}/approve/Approves a listing — status becomes active.
Reject listing#
🔒 Admin/api/admin/listings/{id}/reject/Rejects a listing with a reason — host is notified.
Request body
{ "rejection_reason": "Photos too low quality." }List users#
🔒 Admin/api/admin/users/?role=user&verification_stage=pending_reviewAll users with optional filters.
Approve host#
🔒 Admin/api/admin/users/{id}/approve-host/Reject host#
🔒 Admin/api/admin/users/{id}/reject-host/Request body
{ "rejection_reason": "Identity document unclear." }List bookings#
🔒 Admin/api/admin/bookings/?status=payment_submittedAll bookings with optional filters.
Confirm payment#
🔒 Admin/api/admin/bookings/{id}/confirm-payment/Confirms payment — booking moves to confirmed.
Unpublish review#
🔒 Admin/api/admin/reviews/{id}/unpublish/Hide a review. Recalculates listing rating.
Host Your First Space#
- 1Register and verify your email.
- 2Complete the host profile — personal info + NIDA identity.
- 3Submit your profile for admin review via
POST /api/auth/host/submit/. - 4Wait for admin approval (
verification_stage=approved). - 5Create a listing draft (
POST /api/listings/). - 6Add amenities, pricing, photos and availability.
- 7Submit the listing for review (
POST /api/listings/{id}/submit/). - 8Listing goes live after admin approval.
Complete a Booking#
- 1Browse listings (
GET /api/listings/). - 2Pick dates and create an intent (
POST /api/bookings/intents/) — 15-minute hold begins. - 3Review the price snapshot from the intent response.
- 4Confirm the booking (
POST /api/bookings/create/). - 5Upload payment proof (
PATCH /api/bookings/{id}/submit-payment/). - 6Admin confirms payment — booking is confirmed.
- 7Show up on the check-in date.
- 8After checkout, receive a review prompt via email / SMS.
Admin Workflow#
- 1Login as admin.
- 2Review pending host applications (
GET /api/admin/users/?verification_stage=pending_review). - 3Approve or reject hosts.
- 4Review pending listings (
GET /api/admin/listings/?status=pending_review). - 5Approve or reject listings with a reason.
- 6Monitor bookings and confirm payments.
- 7Check SMS balance (
GET /api/admin/sms/balance/).