MENU navbar-image

Introduction

This documentation aims to provide all the information you need to work with our API.

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_ACCESS_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Authenticate using Laravel Sanctum tokens. Obtain a token by calling POST /api/v1/customer-auth/login-password, POST /api/v1/customer-auth/login-otp, or registration endpoints. Include the token in the Authorization header as: Authorization: Bearer {token}.

Beverages

List beverages

Retrieves a paginated list of beverages with optional filtering

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages?category_id=550e8400-e29b-41d4-a716-446655440000&search=heineken&min_price=1&max_price=5&in_stock=1&sort_by=price&sort_order=asc&page=1&per_page=10"
const url = new URL(
    "https://backend.test/api/v1/beverages"
);

const params = {
    "category_id": "550e8400-e29b-41d4-a716-446655440000",
    "search": "heineken",
    "min_price": "1",
    "max_price": "5",
    "in_stock": "1",
    "sort_by": "price",
    "sort_order": "asc",
    "page": "1",
    "per_page": "10",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "beverages": [
            {
                "id": "bev_123456",
                "name": "Heineken",
                "category": "Beer",
                "subcategory": "Lager",
                "description": "Premium lager beer",
                "alcoholContent": 5,
                "volume": 0.33,
                "price": 2.5,
                "currency": "OMR",
                "imageUrl": "https://example.com/images/heineken.jpg",
                "inStock": true,
                "quantityAvailable": 100
            }
        ],
        "pagination": {
            "currentPage": 1,
            "totalPages": 5,
            "totalItems": 50,
            "itemsPerPage": 10
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (422):


{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid category ID format"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/beverages

Query Parameters

category_id   string  optional    

Filter by category UUID. Example: 550e8400-e29b-41d4-a716-446655440000

search   string  optional    

Search by name. Example: heineken

min_price   number  optional    

Minimum price. Example: 1

max_price   number  optional    

Maximum price. Example: 5

in_stock   boolean  optional    

Only in stock items. Example: true

sort_by   string  optional    

Sort by: price, name, rating, popularity. Example: price

sort_order   string  optional    

Sort order: asc, desc. Example: asc

page   integer  optional    

Page number. Example: 1

per_page   integer  optional    

Items per page. Example: 10

Search beverages by name, brand, description, or SKU

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/search?q=heineken&category_id=550e8400-e29b-41d4-a716-446655440000&min_price=1&max_price=5&page=1&per_page=10"
const url = new URL(
    "https://backend.test/api/v1/beverages/search"
);

const params = {
    "q": "heineken",
    "category_id": "550e8400-e29b-41d4-a716-446655440000",
    "min_price": "1",
    "max_price": "5",
    "page": "1",
    "per_page": "10",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "beverages": [
            {
                "id": "bev_123456",
                "name": "Heineken",
                "price": 2.5,
                "currency": "OMR"
            }
        ],
        "pagination": {
            "currentPage": 1,
            "totalPages": 2,
            "totalItems": 15,
            "itemsPerPage": 10
        }
    }
}
 

Example response (422):


{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "The search query is required"
    }
}
 

Get a list of featured or popular beverages

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/featured?limit=8&type=popular"
const url = new URL(
    "https://backend.test/api/v1/beverages/featured"
);

const params = {
    "limit": "8",
    "type": "popular",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "beverages": [
            {
                "id": "bev_123456",
                "name": "Heineken",
                "ratingAverage": 4.5,
                "ratingCount": 128,
                "price": 2.5,
                "currency": "OMR"
            }
        ]
    }
}
 

Get beverage categories

Retrieves list of all beverage categories with beverage counts

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/categories"
const url = new URL(
    "https://backend.test/api/v1/beverages/categories"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "categories": [
            {
                "id": "cat_123456",
                "name": "Beer",
                "description": "Alcoholic beverages brewed from grains",
                "imageUrl": "https://example.com/images/beer-category.jpg",
                "beveragesCount": 25,
                "subcategories": [
                    {
                        "id": "sub_123456",
                        "name": "Lager",
                        "description": "Light, crisp beer"
                    }
                ]
            }
        ]
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/beverages/categories

Get category details with beverages

Retrieves a specific category and its beverages

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/categories/{categoryId}"
const url = new URL(
    "https://backend.test/api/v1/beverages/categories/{categoryId}"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "category": {
            "id": "550e8400-e29b-41d4-a716-446655440000",
            "name": "Beer",
            "description": "Alcoholic beverages brewed from grains"
        },
        "beverages": [
            {
                "id": "bev_123456",
                "name": "Heineken",
                "price": 2.5,
                "currency": "OMR"
            }
        ],
        "pagination": {
            "currentPage": 1,
            "totalPages": 3,
            "totalItems": 25,
            "itemsPerPage": 10
        }
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "CATEGORY_NOT_FOUND",
        "message": "Category not found"
    }
}
 

Example response (422):


{
    "success": false,
    "error": {
        "code": "VALIDATION_ERROR",
        "message": "Invalid category ID format"
    }
}
 

Request      

GET api/v1/beverages/categories/{categoryId}

Get beverage details

Retrieves detailed information about a specific beverage

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/{id}"
const url = new URL(
    "https://backend.test/api/v1/beverages/{id}"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "beverage": {
            "id": "bev_123456",
            "name": "Heineken",
            "category": "Beer",
            "subcategory": "Lager",
            "description": "Premium lager beer",
            "alcoholContent": 5,
            "volume": 0.33,
            "price": 2.5,
            "currency": "OMR",
            "imageUrl": "https://example.com/images/heineken.jpg",
            "inStock": true,
            "quantityAvailable": 100,
            "origin": "Netherlands",
            "brewery": "Heineken N.V.",
            "ingredients": [
                "Water",
                "Barley",
                "Hops"
            ],
            "nutritionalInfo": {
                "calories": 150,
                "carbohydrates": 11
            }
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "BEVERAGE_NOT_FOUND",
        "message": "Beverage not found"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/beverages/{id}

Check beverage availability

Check if a specific beverage is available in requested quantity

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/{id}/availability?quantity=5"
const url = new URL(
    "https://backend.test/api/v1/beverages/{id}/availability"
);

const params = {
    "quantity": "5",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "available": true,
        "beverage": {
            "id": "bev_123456",
            "name": "Heineken",
            "stockQuantity": 100,
            "maxOrderQuantity": 10
        }
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "BEVERAGE_NOT_FOUND",
        "message": "Beverage not found"
    }
}
 

Request      

GET api/v1/beverages/{id}/availability

Query Parameters

quantity   integer  optional    

Quantity to check. Example: 5

Get beverages related to a specific beverage (same category, similar tags)

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/beverages/{id}/related?limit=4"
const url = new URL(
    "https://backend.test/api/v1/beverages/{id}/related"
);

const params = {
    "limit": "4",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "beverages": [
            {
                "id": "bev_789012",
                "name": "Corona Extra",
                "category": "Beer",
                "price": 2.8,
                "currency": "OMR"
            }
        ]
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "BEVERAGE_NOT_FOUND",
        "message": "Beverage not found"
    }
}
 

Customer Authentication

Authentication endpoints for customer registration, login, and profile management

Register

Register a new customer with full details

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/register" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\",
    \"full_name\": \"Sami Nasir\",
    \"email\": \"sami@example.com\",
    \"date_of_birth\": \"1990-01-15\",
    \"nationality\": \"Omani\",
    \"type\": \"citizen\",
    \"national_id\": \"12345678901\",
    \"passport_number\": \"A12345678\",
    \"password\": \"SecurePass123!\",
    \"verification_id\": \"550e8400-e29b-41d4-a716-446655440000\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/register"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999",
    "full_name": "Sami Nasir",
    "email": "sami@example.com",
    "date_of_birth": "1990-01-15",
    "nationality": "Omani",
    "type": "citizen",
    "national_id": "12345678901",
    "passport_number": "A12345678",
    "password": "SecurePass123!",
    "verification_id": "550e8400-e29b-41d4-a716-446655440000"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
  "success": true,
  "message": "Registration successful",
  "data": {
    "customer": { ... },
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
    "expires_in": 7200,
    "token_type": "Bearer"
  }
}
 

Request      

POST api/v1/customer-auth/register

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

full_name   string     

The full name. Example: Sami Nasir

email   string  optional    

optional The email. Example: sami@example.com

date_of_birth   string  optional    

optional Date of birth (Y-m-d). Example: 1990-01-15

nationality   string  optional    

optional The nationality. Example: Omani

type   string  optional    

optional Customer type: citizen, resident, tourist. Example: citizen

national_id   string  optional    

optional National ID (for citizens). Example: 12345678901

passport_number   string  optional    

optional Passport number (for tourists). Example: A12345678

password   string  optional    

optional The password. Example: SecurePass123!

verification_id   string  optional    

optional Identity verification ID. Example: 550e8400-e29b-41d4-a716-446655440000

Register/Login with Phone OTP

Quick registration or login using phone OTP

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/register-phone" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\",
    \"otp\": \"1234\",
    \"otp_id\": \"550e8400-e29b-41d4-a716-446655440000\",
    \"full_name\": \"Sami Nasir\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/register-phone"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999",
    "otp": "1234",
    "otp_id": "550e8400-e29b-41d4-a716-446655440000",
    "full_name": "Sami Nasir"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
  "success": true,
  "message": "Login successful",
  "data": {
    "customer": { ... },
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
    "expires_in": 7200
  }
}
 

Request      

POST api/v1/customer-auth/register-phone

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

otp   string     

The 4-digit OTP. Example: 1234

otp_id   string     

The OTP ID. Example: 550e8400-e29b-41d4-a716-446655440000

full_name   string  optional    

optional Full name for new registration. Example: Sami Nasir

Login with Password

Login using phone number and password

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/login-password" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\",
    \"password\": \"SecurePass123!\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/login-password"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999",
    "password": "SecurePass123!"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
  "success": true,
  "message": "Login successful",
  "data": {
    "customer": { ... },
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
    "expires_in": 7200
  }
}
 

Request      

POST api/v1/customer-auth/login-password

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

password   string     

The password. Example: SecurePass123!

Login with OTP

Login using phone OTP

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/login-otp" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\",
    \"otp\": \"1234\",
    \"otp_id\": \"550e8400-e29b-41d4-a716-446655440000\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/login-otp"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999",
    "otp": "1234",
    "otp_id": "550e8400-e29b-41d4-a716-446655440000"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
  "success": true,
  "message": "Login successful",
  "data": {
    "customer": { ... },
    "access_token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
    "expires_in": 7200
  }
}
 

Request      

POST api/v1/customer-auth/login-otp

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

otp   string     

The 4-digit OTP. Example: 1234

otp_id   string     

The OTP ID. Example: 550e8400-e29b-41d4-a716-446655440000

Refresh Token

Get new access token using refresh token

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/refresh-token" \
    --header "Content-Type: application/json" \
    --data "{
    \"refresh_token\": \"1|laravel_sanctum_token...\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/refresh-token"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "refresh_token": "1|laravel_sanctum_token..."
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Token refreshed successfully",
    "data": {
        "access_token": "eyJhbGciOiJIUzI1NiIs...",
        "refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
        "expires_in": 7200,
        "token_type": "Bearer"
    }
}
 

Request      

POST api/v1/customer-auth/refresh-token

Headers

Content-Type        

Example: application/json

Body Parameters

refresh_token   string     

The refresh token. Example: 1|laravel_sanctum_token...

Forgot Password

Request password reset OTP

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/forgot-password" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/forgot-password"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "OTP sent successfully",
    "data": {
        "otp_id": "550e8400-e29b-41d4-a716-446655440000",
        "expires_at": "2026-02-27T12:00:00Z"
    }
}
 

Request      

POST api/v1/customer-auth/forgot-password

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

Confirm Forgot Password OTP

Verify OTP for password reset (step 2 of 3)

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/confirm-forgot-password-otp" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\",
    \"otp\": \"1234\",
    \"otp_id\": \"550e8400-e29b-41d4-a716-446655440000\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/confirm-forgot-password-otp"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999",
    "otp": "1234",
    "otp_id": "550e8400-e29b-41d4-a716-446655440000"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "OTP verified successfully. You can now set your new password.",
    "data": {
        "otp_id": "550e8400-e29b-41d4-a716-446655440000",
        "verified": true
    }
}
 

Request      

POST api/v1/customer-auth/confirm-forgot-password-otp

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

otp   string     

The 4-digit OTP. Example: 1234

otp_id   string     

The OTP ID. Example: 550e8400-e29b-41d4-a716-446655440000

Reset Password

Reset password with verified OTP (step 3 of 3) OTP must be confirmed first via confirm-forgot-password-otp endpoint

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/reset-password" \
    --header "Content-Type: application/json" \
    --data "{
    \"otp_id\": \"550e8400-e29b-41d4-a716-446655440000\",
    \"password\": \"NewSecurePass123!\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/reset-password"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "otp_id": "550e8400-e29b-41d4-a716-446655440000",
    "password": "NewSecurePass123!"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Password reset successfully. Please login again.",
    "data": {
        "requires_re_login": true
    }
}
 

Request      

POST api/v1/customer-auth/reset-password

Headers

Content-Type        

Example: application/json

Body Parameters

otp_id   string     

The verified OTP ID. Example: 550e8400-e29b-41d4-a716-446655440000

password   string     

The new password. Example: NewSecurePass123!

Check Phone Exists

Check if a phone number is already registered

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/check-phone" \
    --header "Content-Type: application/json" \
    --data "{
    \"phone_number\": \"+96899999999\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/check-phone"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "phone_number": "+96899999999"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Phone number is registered",
    "data": {
        "exists": true
    }
}
 

Request      

POST api/v1/customer-auth/check-phone

Headers

Content-Type        

Example: application/json

Body Parameters

phone_number   string     

The phone number. Example: +96899999999

Send OTP

requires authentication

Send a one-time password to the authenticated customer's registered phone number. Requires authentication - uses the customer's phone number from the database.

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/send-otp" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"purpose\": \"phone_verification\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/send-otp"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "purpose": "phone_verification"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "OTP sent successfully to your registered phone number",
    "data": {
        "otp_id": "550e8400-e29b-41d4-a716-446655440000",
        "expires_at": "2026-02-27T12:00:00Z",
        "expires_in_seconds": 600
    }
}
 

Example response (403):


{
    "success": false,
    "message": "Phone number not found",
    "data": {
        "code": "PHONE_NOT_FOUND"
    }
}
 

Request      

POST api/v1/customer-auth/send-otp

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

purpose   string  optional    

optional The purpose of OTP. Example: phone_verification

Verify Phone OTP

requires authentication

Verify the OTP code sent to the authenticated customer's registered phone number. Also updates the customer's is_phone_verified status to true upon success.

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/verify-phone-otp" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"otp\": \"1234\",
    \"otp_id\": \"550e8400-e29b-41d4-a716-446655440000\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/verify-phone-otp"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "otp": "1234",
    "otp_id": "550e8400-e29b-41d4-a716-446655440000"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Phone number verified successfully",
    "data": {
        "phone_number": "+96899999999"
    }
}
 

Request      

POST api/v1/customer-auth/verify-phone-otp

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

otp   string     

The 4-digit OTP code. Example: 1234

otp_id   string     

The OTP ID returned from send OTP. Example: 550e8400-e29b-41d4-a716-446655440000

Resend OTP

requires authentication

Resend OTP to the authenticated customer's registered phone number.

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/resend-otp" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"purpose\": \"phone_verification\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/resend-otp"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "purpose": "phone_verification"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "OTP resent successfully",
    "data": {
        "otp_id": "550e8400-e29b-41d4-a716-446655440000",
        "expires_at": "2026-02-27T12:00:00Z"
    }
}
 

Request      

POST api/v1/customer-auth/resend-otp

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

purpose   string  optional    

optional The purpose of OTP. Example: phone_verification

Get Verification Status

requires authentication

Get the current verification status of the authenticated customer. Returns the current status of phone and THEQA verification, along with required next steps.

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/customer-auth/verification-status" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/verification-status"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Verification status retrieved",
    "data": {
        "is_fully_verified": false,
        "current_status": {
            "is_phone_verified": false,
            "is_theqa_verified": false
        },
        "customer_type": "citizen",
        "steps": [
            {
                "step": 1,
                "type": "phone_verification",
                "title": "Verify Phone Number",
                "description": "Verify your phone number via OTP",
                "endpoint": "POST /api/v1/customer-auth/send-otp",
                "status": "pending"
            }
        ]
    }
}
 

Request      

GET api/v1/customer-auth/verification-status

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Initiate Identity Verification (Citizens/Residents)

requires authentication

Start THEQA identity verification for citizens and residents

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/initiate-identity" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"national_id\": \"12345678901\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/initiate-identity"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "national_id": "12345678901"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Identity verification initiated",
    "data": {
        "verification_id": "550e8400-e29b-41d4-a716-446655440000",
        "reference": "THEQA_REF_123",
        "redirect_url": "https://theqa.gov.om/verify/abc123"
    }
}
 

Request      

POST api/v1/customer-auth/initiate-identity

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

national_id   string     

The national ID. Example: 12345678901

Handle Identity Callback

Handle THEQA callback after identity verification

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/identity-callback" \
    --header "Content-Type: application/json" \
    --data "{
    \"reference\": \"THEQA_REF_123\",
    \"status\": \"success\",
    \"reason\": \"User cancelled\",
    \"identity_data\": []
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/identity-callback"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "reference": "THEQA_REF_123",
    "status": "success",
    "reason": "User cancelled",
    "identity_data": []
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Identity verification completed",
    "data": {
        "verification_id": "550e8400-e29b-41d4-a716-446655440000",
        "status": "completed"
    }
}
 

Request      

POST api/v1/customer-auth/identity-callback

Headers

Content-Type        

Example: application/json

Body Parameters

reference   string     

THEQA reference. Example: THEQA_REF_123

status   string     

Status: success or failed. Example: success

reason   string  optional    

optional Failure reason. Example: User cancelled

identity_data   object  optional    

optional Identity data on success.

Verify Tourist Passport

Verify tourist identity using passport

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/verify-tourist" \
    --header "Content-Type: application/json" \
    --data "{
    \"passport_number\": \"A12345678\",
    \"nationality\": \"British\",
    \"full_name\": \"John Smith\",
    \"date_of_birth\": \"1988-12-03\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/verify-tourist"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "passport_number": "A12345678",
    "nationality": "British",
    "full_name": "John Smith",
    "date_of_birth": "1988-12-03"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Passport verified successfully",
    "data": {
        "verification_id": "550e8400-e29b-41d4-a716-446655440000",
        "passport_data": {
            "passport_number": "A12345678",
            "nationality": "British",
            "full_name": "John Smith",
            "date_of_birth": "1988-12-03"
        }
    }
}
 

Request      

POST api/v1/customer-auth/verify-tourist

Headers

Content-Type        

Example: application/json

Body Parameters

passport_number   string     

The passport number. Example: A12345678

nationality   string     

The nationality. Example: British

full_name   string     

The full name. Example: John Smith

date_of_birth   string     

Date of birth (Y-m-d). Example: 1988-12-03

Logout

requires authentication

Logout the authenticated customer

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/logout" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"refresh_token\": \"architecto\",
    \"all_devices\": false
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/logout"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "refresh_token": "architecto",
    "all_devices": false
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Logged out successfully",
    "data": {
        "all_devices": false
    }
}
 

Request      

POST api/v1/customer-auth/logout

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

refresh_token   string  optional    

optional The refresh token to revoke. Example: architecto

all_devices   boolean  optional    

optional Logout from all devices. Example: false

Set Password

requires authentication

Set or change password (authenticated)

Example request:
curl --request POST \
    "https://backend.test/api/v1/customer-auth/set-password" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"password\": \"NewSecurePass123!\",
    \"current_password\": \"OldPass123!\",
    \"logout_other_devices\": true
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/set-password"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "password": "NewSecurePass123!",
    "current_password": "OldPass123!",
    "logout_other_devices": true
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Password updated successfully"
}
 

Request      

POST api/v1/customer-auth/set-password

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

password   string     

The new password. Example: NewSecurePass123!

current_password   string  optional    

optional Current password (required if changing). Example: OldPass123!

logout_other_devices   boolean  optional    

optional Logout other devices. Example: true

Get Profile

requires authentication

Get authenticated customer profile

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/customer-auth/profile" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/profile"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Profile retrieved successfully",
    "data": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "full_name": "Sami Nasir",
        "first_name": "Sami",
        "phone_number": "+96899999999",
        "email": "sami@example.com",
        "date_of_birth": "1990-01-15",
        "nationality": "Omani",
        "type": "citizen",
        "is_active": true,
        "preferences": {
            "language": "en",
            "notifications": true
        },
        "verification": {
            "is_fully_verified": true,
            "is_phone_verified": true,
            "is_theqa_verified": true
        },
        "travel_status": {
            "has_boarding_pass": true,
            "active_boarding_pass": {
                "id": "550e8400-e29b-41d4-a716-446655440001",
                "flight_number": "WY123",
                "departure_time": "2026-03-05T10:00:00Z"
            }
        }
    }
}
 

Request      

GET api/v1/customer-auth/profile

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Update Profile

requires authentication

Update authenticated customer profile

Example request:
curl --request PUT \
    "https://backend.test/api/v1/customer-auth/profile" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"full_name\": \"Sami Al-Nasir\",
    \"email\": \"sami@example.com\",
    \"date_of_birth\": \"1990-01-15\",
    \"nationality\": \"Omani\",
    \"preferences\": []
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/profile"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "full_name": "Sami Al-Nasir",
    "email": "sami@example.com",
    "date_of_birth": "1990-01-15",
    "nationality": "Omani",
    "preferences": []
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Profile updated successfully",
    "data": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "full_name": "Sami Al-Nasir",
        "first_name": "Sami",
        "phone_number": "+96899999999",
        "email": "sami.updated@example.com",
        "date_of_birth": "1990-01-15",
        "nationality": "Omani",
        "type": "citizen",
        "is_active": true,
        "preferences": {
            "language": "ar",
            "notifications": false
        },
        "verification": {
            "is_fully_verified": true,
            "is_phone_verified": true,
            "is_theqa_verified": true
        },
        "travel_status": {
            "has_boarding_pass": true,
            "active_boarding_pass": null
        }
    }
}
 

Request      

PUT api/v1/customer-auth/profile

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

full_name   string  optional    

optional The full name. Example: Sami Al-Nasir

email   string  optional    

optional The email. Example: sami@example.com

date_of_birth   string  optional    

optional Date of birth (Y-m-d). Example: 1990-01-15

nationality   string  optional    

optional The nationality. Example: Omani

preferences   object  optional    

optional Preferences object.

Delete Account

requires authentication

Delete authenticated customer account

Example request:
curl --request DELETE \
    "https://backend.test/api/v1/customer-auth/account" \
    --header "Authorization: Bearer {YOUR_ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --data "{
    \"password\": \"MyPass123!\",
    \"reason\": \"No longer needed\"
}"
const url = new URL(
    "https://backend.test/api/v1/customer-auth/account"
);

const headers = {
    "Authorization": "Bearer {YOUR_ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "password": "MyPass123!",
    "reason": "No longer needed"
};

fetch(url, {
    method: "DELETE",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "message": "Account deleted successfully"
}
 

Request      

DELETE api/v1/customer-auth/account

Headers

Authorization        

Example: Bearer {YOUR_ACCESS_TOKEN}

Content-Type        

Example: application/json

Body Parameters

password   string  optional    

optional Password confirmation (if set). Example: MyPass123!

reason   string  optional    

optional Reason for deletion. Example: No longer needed

Customer Management

Get customer statistics

Retrieves customer purchase statistics

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/customers/statistics"
const url = new URL(
    "https://backend.test/api/v1/customers/statistics"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "statistics": {
            "totalOrders": 5,
            "totalSpent": 45.5,
            "totalVolume": 3.5,
            "averageOrderValue": 9.1,
            "favoriteCategory": "Beer",
            "lastOrderAt": "2026-02-03T10:30:00Z",
            "memberSince": "2026-01-01T00:00:00Z"
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/customers/statistics

Eligibility

Check travel status

Checks if user has valid travel status to purchase duty-free items

Example request:
curl --request POST \
    "https://backend.test/api/v1/eligibility/check"
const url = new URL(
    "https://backend.test/api/v1/eligibility/check"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "status": "ELIGIBLE",
        "message": "Valid travel ticket found",
        "details": {
            "flightNumber": "WY123",
            "departureDate": "2026-02-03",
            "destination": "MCT",
            "eligibilityExpiry": "2026-02-04T00:00:00Z",
            "remainingAllowance": {
                "volume": 4,
                "currency": "OMR",
                "amount": 500
            }
        },
        "checkedAt": "2026-02-03T10:00:00Z"
    }
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "INVALID_REQUEST",
        "message": "Request body validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (403):


{
    "success": false,
    "error": {
        "code": "INELIGIBLE",
        "message": "You do not have a valid ticket to view the beverage menu",
        "details": {
            "reason": "NO_VALID_TICKET",
            "suggestion": "Please scan your boarding pass"
        }
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/eligibility/check

Validate boarding pass

Validates boarding pass data from scan

Example request:
curl --request POST \
    "https://backend.test/api/v1/eligibility/validate-boarding-pass"
const url = new URL(
    "https://backend.test/api/v1/eligibility/validate-boarding-pass"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "isValid": true,
        "boardingPassId": "bp_abc123",
        "passengerName": "John Smith",
        "flightDetails": {
            "flightNumber": "WY123",
            "airline": "Oman Air",
            "departure": {
                "airport": "DXB",
                "time": "2026-02-03T15:00:00Z",
                "gate": "A12"
            },
            "arrival": {
                "airport": "MCT",
                "time": "2026-02-03T16:30:00Z"
            }
        },
        "eligibility": {
            "status": "ELIGIBLE",
            "validFrom": "2026-02-03T10:00:00Z",
            "validUntil": "2026-02-04T00:00:00Z",
            "maxVolume": 4
        }
    },
    "message": "Boarding pass validated successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "BOARDING_PASS_INVALID",
        "message": "Boarding pass validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/eligibility/validate-boarding-pass

Endpoints

GET api/health

Example request:
curl --request GET \
    --get "https://backend.test/api/health"
const url = new URL(
    "https://backend.test/api/health"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Request      

GET api/health

Orders

List orders

Retrieves a paginated list of user's orders with optional filtering

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/orders"
const url = new URL(
    "https://backend.test/api/v1/orders"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "orders": [
            {
                "id": "ord_123456",
                "orderNumber": "OP-20260203-001",
                "status": "delivered",
                "total": 25.5,
                "currency": "OMR",
                "itemCount": 3,
                "createdAt": "2026-02-03T10:30:00Z",
                "estimatedDelivery": "2026-02-03T11:00:00Z"
            }
        ],
        "pagination": {
            "currentPage": 1,
            "totalPages": 3,
            "totalItems": 25,
            "itemsPerPage": 10
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/orders

Create order

Creates a new order from the user's cart

Example request:
curl --request POST \
    "https://backend.test/api/v1/orders"
const url = new URL(
    "https://backend.test/api/v1/orders"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (201):


{
    "success": true,
    "data": {
        "order": {
            "id": "ord_123456",
            "orderNumber": "OP-20260203-001",
            "status": "pending",
            "items": [
                {
                    "id": "item_123456",
                    "beverageId": "bev_123456",
                    "name": "Heineken",
                    "quantity": 2,
                    "unitPrice": 2.5,
                    "totalPrice": 5
                }
            ],
            "subtotal": 5,
            "tax": 0.25,
            "deliveryFee": 1,
            "total": 6.25,
            "currency": "OMR",
            "deliveryAddress": {
                "street": "123 Main St",
                "city": "Muscat",
                "postalCode": "100"
            },
            "estimatedDelivery": "2026-02-03T11:00:00Z",
            "createdAt": "2026-02-03T10:30:00Z"
        }
    },
    "message": "Order created successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "INVALID_REQUEST",
        "message": "Request body validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (422):


{
    "success": false,
    "error": {
        "code": "EMPTY_CART",
        "message": "Cannot create order with empty cart"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/orders

Get order details

Retrieves detailed information about a specific order

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/orders/{orderId}"
const url = new URL(
    "https://backend.test/api/v1/orders/{orderId}"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "order": {
            "id": "ord_123456",
            "orderNumber": "OP-20260203-001",
            "status": "delivered",
            "items": [
                {
                    "id": "item_123456",
                    "beverageId": "bev_123456",
                    "name": "Heineken",
                    "quantity": 2,
                    "unitPrice": 2.5,
                    "totalPrice": 5,
                    "imageUrl": "https://example.com/images/heineken.jpg"
                }
            ],
            "subtotal": 5,
            "tax": 0.25,
            "deliveryFee": 1,
            "total": 6.25,
            "currency": "OMR",
            "deliveryAddress": {
                "street": "123 Main St",
                "city": "Muscat",
                "postalCode": "100"
            },
            "paymentMethod": "card",
            "paymentStatus": "paid",
            "estimatedDelivery": "2026-02-03T11:00:00Z",
            "actualDelivery": "2026-02-03T10:55:00Z",
            "createdAt": "2026-02-03T10:30:00Z",
            "updatedAt": "2026-02-03T10:55:00Z"
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "ORDER_NOT_FOUND",
        "message": "Order not found"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/orders/{orderId}

Track order

Retrieves real-time tracking information for an order

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/orders/{orderId}/tracking"
const url = new URL(
    "https://backend.test/api/v1/orders/{orderId}/tracking"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "tracking": {
            "orderId": "ord_123456",
            "orderNumber": "OP-20260203-001",
            "status": "out_for_delivery",
            "currentLocation": {
                "lat": 23.5859,
                "lng": 58.4059,
                "address": "Al Khuwair, Muscat"
            },
            "estimatedDelivery": "2026-02-03T11:00:00Z",
            "driverInfo": {
                "name": "Ahmed",
                "phone": "+96899999999",
                "vehicleNumber": "OM-1234"
            },
            "timeline": [
                {
                    "status": "order_placed",
                    "timestamp": "2026-02-03T10:30:00Z",
                    "description": "Order placed successfully"
                },
                {
                    "status": "confirmed",
                    "timestamp": "2026-02-03T10:32:00Z",
                    "description": "Order confirmed by store"
                },
                {
                    "status": "out_for_delivery",
                    "timestamp": "2026-02-03T10:45:00Z",
                    "description": "Order is out for delivery"
                }
            ]
        }
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "ORDER_NOT_FOUND",
        "message": "Order not found"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/orders/{orderId}/tracking

Cancel order

Cancels an order that has not yet been delivered

Example request:
curl --request POST \
    "https://backend.test/api/v1/orders/{orderId}/cancel"
const url = new URL(
    "https://backend.test/api/v1/orders/{orderId}/cancel"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "order": {
            "id": "ord_123456",
            "orderNumber": "OP-20260203-001",
            "status": "cancelled",
            "cancelledAt": "2026-02-03T10:35:00Z",
            "cancellationReason": "Changed my mind"
        }
    },
    "message": "Order cancelled successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "CANNOT_CANCEL",
        "message": "Order cannot be cancelled at this stage"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (404):


{
    "success": false,
    "error": {
        "code": "ORDER_NOT_FOUND",
        "message": "Order not found"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/orders/{orderId}/cancel

Payments

Process payment

Processes payment for an order

Example request:
curl --request POST \
    "https://backend.test/api/v1/payments/process"
const url = new URL(
    "https://backend.test/api/v1/payments/process"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "payment": {
            "id": "pay_xyz789",
            "orderId": "ord_abc123def456",
            "status": "completed",
            "amount": 9.9,
            "currency": "OMR",
            "method": "credit_card",
            "transactionId": "txn_abc123xyz",
            "processedAt": "2026-02-03T10:30:05Z"
        },
        "order": {
            "id": "ord_abc123def456",
            "status": "preparing",
            "qrCode": "QR_ord_abc123def456"
        }
    },
    "message": "Payment processed successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "INVALID_PAYMENT",
        "message": "Payment validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (402):


{
    "success": false,
    "error": {
        "code": "PAYMENT_FAILED",
        "message": "Payment processing failed"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/payments/process

Get payment methods

Retrieves saved payment methods for user

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/payments/methods"
const url = new URL(
    "https://backend.test/api/v1/payments/methods"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "paymentMethods": [
            {
                "id": "pm_abc123",
                "type": "credit_card",
                "brand": "visa",
                "lastFourDigits": "4242",
                "expiryMonth": "12",
                "expiryYear": "2028",
                "isDefault": true,
                "createdAt": "2026-01-01T00:00:00Z"
            }
        ]
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/payments/methods

Shopping Cart

Get cart contents

Retrieves current user's shopping cart with all items

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/cart"
const url = new URL(
    "https://backend.test/api/v1/cart"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "cart": {
            "id": "cart_123456",
            "items": [],
            "totalItems": 0,
            "subtotal": 0,
            "total": 0,
            "currency": "OMR"
        }
    }
}
 

Request      

GET api/v1/cart

Add item to cart

Adds a beverage to the user's shopping cart

Example request:
curl --request POST \
    "https://backend.test/api/v1/cart/items"
const url = new URL(
    "https://backend.test/api/v1/cart/items"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Request      

POST api/v1/cart/items

Update cart item

Updates the quantity of an item in the cart

Example request:
curl --request PUT \
    "https://backend.test/api/v1/cart/items/{itemId}"
const url = new URL(
    "https://backend.test/api/v1/cart/items/{itemId}"
);



fetch(url, {
    method: "PUT",
}).then(response => response.json());

Request      

PUT api/v1/cart/items/{itemId}

Remove item from cart

Removes a specific item from the user's cart

Example request:
curl --request DELETE \
    "https://backend.test/api/v1/cart/items/{itemId}"
const url = new URL(
    "https://backend.test/api/v1/cart/items/{itemId}"
);



fetch(url, {
    method: "DELETE",
}).then(response => response.json());

Request      

DELETE api/v1/cart/items/{itemId}

Clear cart

Removes all items from the user's cart

Example request:
curl --request DELETE \
    "https://backend.test/api/v1/cart"
const url = new URL(
    "https://backend.test/api/v1/cart"
);



fetch(url, {
    method: "DELETE",
}).then(response => response.json());

Request      

DELETE api/v1/cart

Support

Get FAQs

Retrieves frequently asked questions

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/support/faqs"
const url = new URL(
    "https://backend.test/api/v1/support/faqs"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "faqs": [
            {
                "id": "faq_123",
                "category": "orders",
                "question": "What is the volume limit?",
                "answer": "The volume limit is 4 liters per order...",
                "isPopular": true
            }
        ],
        "categories": [
            {
                "id": "orders",
                "name": "Orders",
                "count": 10
            },
            {
                "id": "payment",
                "name": "Payment",
                "count": 8
            }
        ]
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

GET api/v1/support/faqs

Retrieves active legal declarations sorted by order

Example request:
curl --request GET \
    --get "https://backend.test/api/v1/support/legal-declarations"
const url = new URL(
    "https://backend.test/api/v1/support/legal-declarations"
);



fetch(url, {
    method: "GET",
}).then(response => response.json());

Example response (200):


{
    "success": true,
    "data": {
        "declarations": [
            {
                "id": "ld_123",
                "type": "warning",
                "content": "Important Notice...",
                "sortOrder": 1
            }
        ]
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Contact support

Submits a support request

Example request:
curl --request POST \
    "https://backend.test/api/v1/support/contact"
const url = new URL(
    "https://backend.test/api/v1/support/contact"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (201):


{
    "success": true,
    "data": {
        "ticketId": "tk_abc123",
        "status": "open",
        "createdAt": "2026-02-03T11:00:00Z",
        "estimatedResponse": "24 hours"
    },
    "message": "Support ticket created successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "INVALID_REQUEST",
        "message": "Request body validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/support/contact

order support

Submits a support request for an order

Example request:
curl --request POST \
    "https://backend.test/api/v1/support/order-ticket"
const url = new URL(
    "https://backend.test/api/v1/support/order-ticket"
);



fetch(url, {
    method: "POST",
}).then(response => response.json());

Example response (201):


{
    "success": true,
    "data": {
        "ticketId": "tk_abc123",
        "status": "open",
        "createdAt": "2026-02-03T11:00:00Z",
        "estimatedResponse": "24 hours"
    },
    "message": "Support ticket created successfully"
}
 

Example response (400):


{
    "success": false,
    "error": {
        "code": "INVALID_REQUEST",
        "message": "Request body validation failed"
    }
}
 

Example response (401):


{
    "success": false,
    "error": {
        "code": "UNAUTHORIZED",
        "message": "Invalid or missing authentication"
    }
}
 

Example response (500):


{
    "success": false,
    "error": {
        "code": "INTERNAL_ERROR",
        "message": "Internal server error"
    }
}
 

Request      

POST api/v1/support/order-ticket