Skip to main content

API Reference

REST API endpoints for Talbino MVP. Base URL: https://api.talbino.com/api/v1

Authentication

All endpoints except auth endpoints require JWT token in header:

Authorization: Bearer `{jwt_token}`

Standard Response Format

Success Response

{
"success": true,
"data": { ... },
"message": "Operation successful"
}

Error Response

{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Validation failed",
"details": {
"phone_number": ["Phone number is required"]
}
}
}

HTTP Status Codes

  • 200 OK - Success
  • 201 Created - Resource created
  • 400 Bad Request - Validation error
  • 401 Unauthorized - Missing/invalid token
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found
  • 422 Unprocessable Entity - Business logic error
  • 429 Too Many Requests - Rate limit exceeded
  • 500 Internal Server Error - Server error

Authentication Endpoints

POST /auth/request-otp

Request OTP code for phone number.

Request:

{
"phone_number": "+201234567890"
}

Response: 200 OK

{
"success": true,
"data": {
"expires_at": "2026-02-26T22:40:00Z",
"message": "OTP sent to +201234567890"
}
}

Errors:

  • 429 - Too many OTP requests (max 3 per 10 minutes)
  • 400 - Invalid phone number format

Rate Limit: 3 requests per 10 minutes per phone number


POST /auth/verify-otp

Verify OTP and get JWT tokens.

Request:

{
"phone_number": "+201234567890",
"otp_code": "123456"
}

Response: 200 OK

{
"success": true,
"data": {
"user": {
"id": "uuid",
"phone_number": "+201234567890",
"name": null,
"avatar_url": null,
"language": "ar",
"is_admin": false,
"has_seller_profile": false,
"created_at": "2026-02-26T22:30:00Z"
},
"tokens": {
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"expires_in": 86400
}
}
}

Errors:

  • 401 - Invalid OTP code
  • 401 - OTP expired
  • 401 - Too many attempts (max 3)

POST /auth/refresh

Refresh access token using refresh token.

Request:

{
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc..."
}

Response: 200 OK

{
"success": true,
"data": {
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
"expires_in": 86400
}
}

POST /auth/logout

Logout and invalidate tokens.

Headers: Authorization: Bearer {token}

Request:

{
"device_token": "fcm_token_here"
}

Response: 200 OK

{
"success": true,
"message": "Logged out successfully"
}

User Endpoints

GET /users/me

Get current user profile.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"phone_number": "+201234567890",
"name": "محمد أحمد",
"avatar_url": "https://s3.../avatar.jpg",
"language": "ar",
"is_admin": false,
"seller_profile": {
"id": "uuid",
"status": "approved",
"business_name": "Ahmed's Electronics",
"location_district": "Nasr City",
"rating_avg": 4.5,
"rating_count": 23
},
"created_at": "2026-02-26T22:30:00Z"
}
}

PUT /users/me

Update current user profile.

Headers: Authorization: Bearer {token}

Request:

{
"name": "محمد أحمد",
"language": "ar"
}

Response: 200 OK

{
"success": true,
"data": { ... }
}

POST /users/me/avatar

Upload user avatar.

Headers:

  • Authorization: Bearer {token}
  • Content-Type: multipart/form-data

Request:

avatar: [file]

Response: 200 OK

{
"success": true,
"data": {
"avatar_url": "https://s3.../avatar.jpg"
}
}

POST /device-tokens

Register device token for push notifications.

Headers: Authorization: Bearer {token}

Request:

{
"platform": "ios",
"push_token": "fcm_token_here"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"platform": "ios",
"created_at": "2026-02-26T22:30:00Z"
}
}

Buy Request Endpoints

POST /requests

Create a new buy request.

Headers: Authorization: Bearer {token}

Request:

{
"category": "phone",
"product_brand": "Apple",
"product_model": "iPhone 13",
"condition_pref": "like_new",
"budget_min": 8000,
"budget_max": 10000,
"location_district": "Nasr City",
"location_city": "Cairo",
"notes": "Prefer 128GB, any color"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"buyer_id": "uuid",
"category": "phone",
"product_brand": "Apple",
"product_model": "iPhone 13",
"condition_pref": "like_new",
"budget_min": 8000,
"budget_max": 10000,
"location_district": "Nasr City",
"location_city": "Cairo",
"notes": "Prefer 128GB, any color",
"status": "active",
"offer_count": 0,
"created_at": "2026-02-26T22:30:00Z"
}
}

Validation:

  • category: Required, enum (phone, accessory)
  • budget_min: Required, numeric, > 0
  • budget_max: Required, numeric, >= budget_min
  • location_district: Required

GET /requests

List buy requests (for sellers to browse).

Headers: Authorization: Bearer {token}

Query Parameters:

  • category (optional): Filter by category
  • location_city (optional): Filter by city
  • status (optional): Filter by status (default: active)
  • page (optional): Page number (default: 1)
  • per_page (optional): Items per page (default: 20, max: 50)

Response: 200 OK

{
"success": true,
"data": {
"requests": [
{
"id": "uuid",
"category": "phone",
"product_brand": "Apple",
"product_model": "iPhone 13",
"condition_pref": "like_new",
"budget_min": 8000,
"budget_max": 10000,
"location_district": "Nasr City",
"status": "active",
"offer_count": 3,
"created_at": "2026-02-26T22:30:00Z"
}
],
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 45,
"last_page": 3
}
}
}

Authorization: Any authenticated user can browse


GET /requests/my

List current user's buy requests.

Headers: Authorization: Bearer {token}

Query Parameters:

  • status (optional): Filter by status
  • page, per_page

Response: 200 OK (same format as GET /requests)


GET /requests/{id}

Get buy request details.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"buyer": {
"id": "uuid",
"name": "محمد أحمد"
},
"category": "phone",
"product_brand": "Apple",
"product_model": "iPhone 13",
"condition_pref": "like_new",
"budget_min": 8000,
"budget_max": 10000,
"location_district": "Nasr City",
"location_city": "Cairo",
"notes": "Prefer 128GB, any color",
"status": "active",
"offer_count": 3,
"created_at": "2026-02-26T22:30:00Z",
"closed_at": null
}
}

PUT /requests/{id}/close

Close a buy request manually.

Headers: Authorization: Bearer {token}

Authorization: Only request owner

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"status": "closed",
"closed_at": "2026-02-26T23:00:00Z"
}
}

Errors:

  • 403 - Not request owner
  • 422 - Request already closed

Offer Endpoints

POST /offers

Create an offer on a buy request.

Headers: Authorization: Bearer {token}

Request:

{
"request_id": "uuid",
"price": 9500,
"availability": "Immediate",
"condition_notes": "Excellent condition, 95% battery health",
"warranty_notes": "6 months warranty included"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"request_id": "uuid",
"seller_id": "uuid",
"price": 9500,
"availability": "Immediate",
"condition_notes": "Excellent condition, 95% battery health",
"warranty_notes": "6 months warranty included",
"status": "pending",
"created_at": "2026-02-26T22:35:00Z"
}
}

Authorization: Only approved sellers

Validation:

  • Request must be active
  • Seller must be approved
  • Price should be within budget range (warning if outside)

Errors:

  • 403 - Seller not approved
  • 422 - Request not active
  • 422 - Seller already has pending offer on this request

GET /requests/{request_id}/offers

List offers for a buy request.

Headers: Authorization: Bearer {token}

Authorization: Request owner or offer sellers

Response: 200 OK

{
"success": true,
"data": {
"offers": [
{
"id": "uuid",
"seller": {
"id": "uuid",
"name": "Ahmed's Electronics",
"rating_avg": 4.5,
"rating_count": 23,
"location_district": "Nasr City"
},
"price": 9500,
"availability": "Immediate",
"condition_notes": "Excellent condition",
"warranty_notes": "6 months warranty",
"status": "pending",
"created_at": "2026-02-26T22:35:00Z"
}
]
}
}

GET /offers/my

List current user's offers (for sellers).

Headers: Authorization: Bearer {token}

Query Parameters:

  • status (optional): Filter by status
  • page, per_page

Response: 200 OK

{
"success": true,
"data": {
"offers": [
{
"id": "uuid",
"request": {
"id": "uuid",
"product_brand": "Apple",
"product_model": "iPhone 13",
"budget_max": 10000
},
"price": 9500,
"status": "pending",
"created_at": "2026-02-26T22:35:00Z"
}
],
"pagination": { ... }
}
}

POST /offers/{id}/accept

Accept an offer (buyer only).

Headers: Authorization: Bearer {token}

Authorization: Only request owner

Response: 200 OK

{
"success": true,
"data": {
"deal": {
"id": "uuid",
"request_id": "uuid",
"offer_id": "uuid",
"buyer_id": "uuid",
"seller_id": "uuid",
"status": "accepted",
"created_at": "2026-02-26T22:40:00Z"
}
}
}

Side Effects:

  • Creates deal
  • Sets offer status to accepted
  • Rejects all other offers
  • Closes buy request
  • Sends push notifications

Errors:

  • 403 - Not request owner
  • 422 - Offer already accepted/rejected
  • 422 - Request not active

DELETE /offers/{id}

Withdraw an offer (seller only, before acceptance).

Headers: Authorization: Bearer {token}

Authorization: Only offer owner

Response: 200 OK

{
"success": true,
"message": "Offer withdrawn"
}

Errors:

  • 403 - Not offer owner
  • 422 - Offer already accepted

Deal Endpoints

GET /deals/my

List current user's deals (buyer or seller view).

Headers: Authorization: Bearer {token}

Query Parameters:

  • status (optional): Filter by status
  • role (optional): Filter by role (buyer/seller)
  • page, per_page

Response: 200 OK

{
"success": true,
"data": {
"deals": [
{
"id": "uuid",
"request": {
"product_brand": "Apple",
"product_model": "iPhone 13"
},
"offer": {
"price": 9500
},
"buyer": {
"id": "uuid",
"name": "محمد أحمد"
},
"seller": {
"id": "uuid",
"name": "Ahmed's Electronics",
"rating_avg": 4.5
},
"status": "accepted",
"created_at": "2026-02-26T22:40:00Z"
}
],
"pagination": { ... }
}
}

GET /deals/{id}

Get deal details.

Headers: Authorization: Bearer {token}

Authorization: Buyer or seller in deal

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"request": { ... },
"offer": { ... },
"buyer": { ... },
"seller": { ... },
"status": "accepted",
"conversation_id": "uuid",
"created_at": "2026-02-26T22:40:00Z",
"completed_at": null,
"cancelled_at": null
}
}

PUT /deals/{id}/complete

Mark deal as completed (buyer only).

Headers: Authorization: Bearer {token}

Authorization: Only buyer

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"status": "completed",
"completed_at": "2026-02-27T10:00:00Z"
}
}

Side Effects:

  • Triggers rating prompt for buyer

PUT /deals/{id}/cancel

Cancel deal (buyer only).

Headers: Authorization: Bearer {token}

Authorization: Only buyer

Request:

{
"reason": "Seller didn't show",
"description": "Optional additional details"
}

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"status": "cancelled",
"cancelled_at": "2026-02-27T10:00:00Z"
}
}

Chat Endpoints

GET /conversations/my

List current user's conversations.

Headers: Authorization: Bearer {token}

Response: 200 OK

{
"success": true,
"data": {
"conversations": [
{
"id": "uuid",
"offer_id": "uuid",
"other_party": {
"id": "uuid",
"name": "Ahmed's Electronics",
"avatar_url": "..."
},
"last_message": {
"text": "هل المنتج متاح؟",
"created_at": "2026-02-26T22:45:00Z"
},
"unread_count": 2,
"created_at": "2026-02-26T22:35:00Z"
}
]
}
}

GET /conversations/{id}/messages

Get messages in a conversation.

Headers: Authorization: Bearer {token}

Authorization: Participant in conversation

Query Parameters:

  • before (optional): Get messages before this timestamp
  • limit (optional): Max messages (default: 50)

Response: 200 OK

{
"success": true,
"data": {
"messages": [
{
"id": "uuid",
"sender_id": "uuid",
"message_text": "هل المنتج متاح الآن؟",
"read_at": null,
"created_at": "2026-02-26T22:45:00Z"
}
],
"has_more": false
}
}

POST /conversations/{id}/messages

Send a message (via REST, WebSocket preferred for real-time).

Headers: Authorization: Bearer {token}

Request:

{
"message_text": "نعم، المنتج متاح"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"conversation_id": "uuid",
"sender_id": "uuid",
"message_text": "نعم، المنتج متاح",
"created_at": "2026-02-26T22:46:00Z"
}
}

Rating Endpoints

POST /ratings

Submit a rating for a seller.

Headers: Authorization: Bearer {token}

Authorization: Only buyer in completed deal

Request:

{
"deal_id": "uuid",
"rating": 5,
"review_text": "بائع ممتاز، منتج كما وصف"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"deal_id": "uuid",
"seller_id": "uuid",
"rating": 5,
"review_text": "بائع ممتاز، منتج كما وصف",
"created_at": "2026-02-27T10:05:00Z"
}
}

Validation:

  • Deal must be completed
  • One rating per deal
  • Rating must be 1-5

Report Endpoints

POST /reports

Report a seller.

Headers: Authorization: Bearer {token}

Request:

{
"reported_user_id": "uuid",
"deal_id": "uuid",
"reason": "no_show",
"description": "Seller didn't show up at agreed location"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"status": "pending",
"created_at": "2026-02-27T11:00:00Z"
}
}

Validation:

  • reason: enum (fake_offer, no_show, rude, scam, other)

Seller Profile Endpoints

POST /seller-profiles

Apply to become a seller.

Headers: Authorization: Bearer {token}

Request:

{
"business_name": "Ahmed's Electronics",
"location_district": "Nasr City",
"location_city": "Cairo",
"bio": "Selling quality used phones since 2020"
}

Response: 201 Created

{
"success": true,
"data": {
"id": "uuid",
"user_id": "uuid",
"status": "pending",
"business_name": "Ahmed's Electronics",
"location_district": "Nasr City",
"created_at": "2026-02-26T22:00:00Z"
}
}

Errors:

  • 422 - User already has seller profile

GET /seller-profiles/{id}

Get seller profile (public).

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"business_name": "Ahmed's Electronics",
"location_district": "Nasr City",
"bio": "Selling quality used phones since 2020",
"rating_avg": 4.5,
"rating_count": 23,
"created_at": "2026-02-26T22:00:00Z"
}
}

Admin Endpoints

All admin endpoints require is_admin = true.

GET /admin/seller-profiles/pending

List pending seller applications.

Headers: Authorization: Bearer {token}

Authorization: Admin only

Response: 200 OK

{
"success": true,
"data": {
"profiles": [
{
"id": "uuid",
"user": {
"id": "uuid",
"phone_number": "+201234567890",
"name": "Ahmed"
},
"business_name": "Ahmed's Electronics",
"location_district": "Nasr City",
"bio": "...",
"status": "pending",
"created_at": "2026-02-26T22:00:00Z"
}
]
}
}

PUT /admin/seller-profiles/{id}/approve

Approve seller application.

Headers: Authorization: Bearer {token}

Authorization: Admin only

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"status": "approved",
"approved_at": "2026-02-26T23:00:00Z"
}
}

PUT /admin/seller-profiles/{id}/reject

Reject seller application.

Headers: Authorization: Bearer {token}

Authorization: Admin only

Response: 200 OK

{
"success": true,
"data": {
"id": "uuid",
"status": "rejected"
}
}

GET /admin/reports

List all reports.

Headers: Authorization: Bearer {token}

Authorization: Admin only

Query Parameters:

  • status (optional): Filter by status

Response: 200 OK

{
"success": true,
"data": {
"reports": [
{
"id": "uuid",
"reporter": { ... },
"reported_user": { ... },
"deal": { ... },
"reason": "no_show",
"description": "...",
"status": "pending",
"created_at": "2026-02-27T11:00:00Z"
}
]
}
}

PUT /admin/reports/{id}/resolve

Resolve a report.

Headers: Authorization: Bearer {token}

Authorization: Admin only

Request:

{
"action": "warn",
"notes": "Warned seller about no-show"
}

Response: 200 OK


WebSocket Events

Connect to: wss://api.talbino.com/ws

Authentication

{
"type": "auth",
"token": "jwt_token_here"
}

Subscribe to Chat

{
"type": "subscribe",
"channel": "conversation.`{conversation_id}`"
}

Send Message

{
"type": "message",
"conversation_id": "uuid",
"message_text": "Hello"
}

Receive Message

{
"type": "message",
"data": {
"id": "uuid",
"conversation_id": "uuid",
"sender_id": "uuid",
"message_text": "Hello",
"created_at": "2026-02-26T22:45:00Z"
}
}

Rate Limiting

  • Auth endpoints: 10 requests/minute per IP
  • OTP requests: 3 requests/10 minutes per phone
  • General API: 100 requests/minute per user
  • WebSocket: 50 messages/minute per user

Pagination

All list endpoints support pagination:

  • page: Page number (default: 1)
  • per_page: Items per page (default: 20, max: 50)

Response includes:

{
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 100,
"last_page": 5
}
}

Localization

All text responses support Arabic and English based on:

  1. Accept-Language header (ar/en)
  2. User's language preference
  3. Default: Arabic

Error messages and notifications are localized automatically.