مرجع API
أمثلة تفصيلية للطلبات والاستجابات لكل نقطة نهاية.
https://api.mahjoz.io/api/open/v1Orders
/ordersorders:readList orders with pagination and optional filters.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
from | date | No | Filter from date (YYYY-MM-DD) |
to | date | No | Filter to date (YYYY-MM-DD) |
status | string | No | Filter by status |
Response
{
"data": [
{
"id": "uuid",
"order_number": "ORD-001",
"status": "confirmed",
"source": "api",
"customer": { "id": "uuid", "first_name": "...", "last_name": "...", "phone": "..." },
"branch": { "id": "uuid", "name": "Main Branch" },
"items": [
{
"id": "uuid",
"name": "Haircut",
"type": "service",
"price": 100.00,
"quantity": 1,
"discount_amount": 0,
"total": 100.00
}
],
"currency": "SAR",
"total": 150.00,
"created_at": "2026-02-25T10:00:00.000000Z"
}
]
}/orders/{uuid}orders:readGet order detail with items, transactions, and full customer/branch details. Each item includes staff_id.
/ordersorders:writeCreate a new order. If the order includes service items, the API validates the requested time slot before creating it.
Request
{
"team_id": "branch-uuid",
"customer_id": "customer-uuid",
"start": "2026-02-25T10:00:00",
"items": [
{
"id": "service-uuid",
"type": "service",
"staff_id": "staff-uuid",
"quantity": 1,
"unit_amount": 100.00,
"discount_amount": 0,
"option_id": "option-uuid"
},
{
"id": "product-uuid",
"type": "product",
"quantity": 2,
"unit_amount": 25.00
}
],
"note": "Optional note",
"latitude": 24.7136,
"longitude": 46.6753
}| Field | Type | Required | Description |
|---|---|---|---|
team_id | uuid | Yes | Branch UUID |
customer_id | uuid | Yes | Customer UUID |
start | datetime | Yes | Required if items contain a service. ISO 8601. |
items | array | Yes | At least 1 item |
items.*.id | uuid | Yes | Service/Product/Package UUID |
items.*.type | string | Yes | service, product, or package |
items.*.quantity | integer | Yes | Minimum 1 |
items.*.staff_id | uuid | No | Staff or staff label UUID (validated by assignment type) |
items.*.unit_amount | number | No | Override unit price |
items.*.discount_amount | number | No | Discount per item |
items.*.option_id | uuid | No | Service option UUID |
note | string | No | Order note |
latitude | number | No | Order location latitude |
longitude | number | No | Order location longitude |
staff_id is validated based on the service assignment type: single_provider expects a staff UUID, team expects a staff label UUID, multiple_providers does not require it.Response (201)
{
"data": {
"id": "uuid",
"order_number": "ORD-042",
"status": "confirmed",
"currency": "SAR",
"total": 150.00,
"created_at": "2026-02-25T10:30:00.000000Z"
}
}/orders/{uuid}/statusorders:writeChange an order's status. Dispatches the order.status_changed webhook. Responds with the full order detail.
Request
{
"status": "completed",
"note_for_status": "finished on-site"
}| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | One of: confirmed, in-progress, completed, canceled |
note_for_status | string | No | Free-text reason or note attached to the transition |
status equals the order's current status, the call is a no-op. 422 order_has_invoice if you try to cancel an order that already has an invoice. 422 invalid_status_transition if you try to cancel an order that has refunded children. Canceling restores item stock automatically.Availability
/availabilityorders:writeCheck available time slots for a service.
Request
{
"service_id": "service-uuid",
"date": "2026-02-25",
"staff_id": "staff-uuid",
"quantity": 1,
"visible_days": 7,
"next_availability": false
}| Field | Type | Required | Description |
|---|---|---|---|
service_id | uuid | Yes | Service to check |
date | date | Yes | Start date (YYYY-MM-DD) |
staff_id | uuid | No | Specific staff member |
quantity | integer | No | Default 1 |
visible_days | integer | No | Days to check (1-30, default 7) |
next_availability | boolean | No | Find next available slot if none on given date |
Response
{
"data": {
"slots": {
"2026-02-25": ["09:00", "09:30", "10:00", "10:30"],
"2026-02-26": ["09:00", "11:00", "14:00"]
}
}
}Customers
/customerscustomers:readList customers with pagination and optional filters.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
name | string | No | Filter by name |
phone | string | No | Filter by phone |
email | string | No | Filter by email |
/customers/{uuid}customers:readGet customer detail with address, note, blocked status, tax_registration_number, and tags.
/customers/phonecustomers:readFind a customer by exact phone number. Returns the customer or null.
| Field | Type | Required | Description |
|---|---|---|---|
phone | string | Yes | Exact phone number (URL-encode + as %2B) |
/customerscustomers:writeCreate a new customer.
Request
{
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+966500000001",
"phone_country": "SA",
"type": "individual",
"city": "Riyadh",
"address": "123 Main St",
"note": "VIP customer",
"tax_registration_number": "300000000000003"
}| Field | Type | Required | Description |
|---|---|---|---|
first_name | string | Yes | Min 2 chars |
last_name | string | No | Min 2 chars |
email | string | No | Valid email |
phone | string | No | Unique per tenant |
phone_country | string | No | Required with phone, 2-char code (e.g. SA) |
type | string | No | individual or company (default: individual) |
city | string | No | Min 3 chars |
address | string | No | Min 3 chars |
note | string | No | Free text |
tax_registration_number | string | No | 15 digits |
Response (201)
{
"data": {
"id": "uuid",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com",
"phone": "+966500000001",
"type": "individual",
"city": "Riyadh",
"created_at": "2026-02-25T10:30:00.000000Z"
}
}Items (Services & Products)
/itemsitems:readList items (services and products) with pagination. Services include duration; products include cost and stock. Each item includes options array with variants.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
type | string | No | service or product |
name | string | No | Filter by name |
Response
{
"data": [
{
"id": "uuid",
"type": "service",
"sku": "SRV-001",
"name": { "ar": "قص شعر", "en": "Haircut" },
"slug": "haircut",
"status": true,
"price": 100.00,
"offer_price": 80.00,
"currency": "SAR",
"duration": 30,
"options": [
{
"id": "uuid",
"name": "Red Small",
"price": 120.00,
"values": [
{ "option_value_id": "uuid", "option_name": "Color", "value": "Red" },
{ "option_value_id": "uuid", "option_name": "Size", "value": "Small" }
]
}
],
"category": { "id": "uuid", "name": { "ar": "الشعر", "en": "Hair" } },
"branch": { "id": "uuid", "name": "Main Branch" }
}
]
}/items/{uuid}items:readGet item detail. For services, includes staff array with id, name, price, and duration.
Staff (Providers)
/staffstaff:readList staff members with their assigned services.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
name | string | No | Filter by name |
branch_id | uuid | No | Filter by branch UUID |
Response
{
"data": [
{
"id": "uuid",
"name": "Ahmed Ali",
"phone": "+966500000001",
"email": "ahmed@example.com",
"image": "https://...",
"branch": { "id": "uuid", "name": "Main Branch" },
"services": [
{ "id": "uuid", "name": "Haircut", "price": 100.00, "duration": 30 }
]
}
]
}/staff/{uuid}staff:readGet staff member detail with branch and full services list.
Branches
/branchesbranches:readList all active branches for the tenant.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
Response
{
"data": [
{
"id": "uuid",
"name": "Main Branch",
"slug": "main-branch",
"phone": "+966500000001",
"address": "123 Main St, Riyadh",
"latitude": 24.7136,
"longitude": 46.6753,
"location": "in-store",
"status": true
}
]
}Categories
/categoriescategories:readList categories ordered by sort_order.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
branch_id | uuid | No | Filter by branch UUID |
Response
{
"data": [
{
"id": "uuid",
"name": { "ar": "خدمات الشعر", "en": "Hair Services" },
"slug": "hair-services",
"description": { "ar": "...", "en": "..." },
"status": true,
"sort_order": 1,
"branch": { "id": "uuid", "name": "Main Branch" }
}
]
}Payment Methods
Only payment methods of type cash and other are exposed. Gateway-backed methods (card, wallets, bank transfer) are managed from the Mahjoz dashboard.
/payment-methodspayment_methods:readList the tenant's manual payment methods (cash and other types only).
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
Response
{
"data": [
{
"id": "uuid",
"name": { "ar": "نقدي", "en": "Cash" },
"slug": "on_arrival",
"status": true,
"type": { "id": 1, "slug": "cash", "name": "Cash" },
"created_at": "2026-04-10T09:00:00.000000Z",
"updated_at": "2026-04-10T09:00:00.000000Z"
}
]
}/payment-methods/{uuid}payment_methods:readGet a single payment method by UUID. Returns 404 if the method's type is not cash or other.
/payment-methodspayment_methods:writeCreate a manual payment method restricted to cash or other types.
Request
{
"name": "Bank Transfer - Al Rajhi",
"type": "other",
"status": true
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name (max 255 chars) |
type | string | Yes | cash or other |
status | boolean | No | Enabled (default true) |
Response (201)
{
"data": {
"id": "uuid",
"name": { "en": "Bank Transfer - Al Rajhi" },
"slug": null,
"status": true,
"type": { "id": 4, "slug": "other", "name": "Other" },
"created_at": "2026-04-15T18:00:00.000000Z",
"updated_at": "2026-04-15T18:00:00.000000Z"
}
}Transactions
/transactionstransactions:readList transactions for the tenant with optional filters.
| Field | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number |
per_page | integer | No | Items per page (max 100) |
status | string | No | Filter by transaction status (e.g. confirmed, pending) |
order_id | uuid | No | Filter by order UUID |
booking_id | uuid | No | Filter by booking UUID |
from | date | No | Filter from date (YYYY-MM-DD) |
to | date | No | Filter to date (YYYY-MM-DD) |
Response
{
"data": [
{
"id": "uuid",
"transaction_no": "TRX-0042",
"amount": "100.00",
"currency": "SAR",
"status": "confirmed",
"is_deposit": false,
"note": "Paid in full",
"date": "2026-04-15T18:00:00.000000Z",
"payment_method": { "id": "uuid", "name": "Cash", "slug": "on_arrival" },
"order": { "id": "uuid", "order_number": "ORD-001" },
"booking": null,
"created_at": "2026-04-15T18:00:00.000000Z",
"updated_at": "2026-04-15T18:00:00.000000Z"
}
]
}/transactions/{uuid}transactions:readGet a single transaction by UUID with its payment method, order, and booking relations.
/orders/{order}/paymentstransactions:writeRecord a payment against an order. The amount cannot exceed the order's remaining unpaid balance, and the order must not be in draft status.
Request
{
"amount": 100.00,
"payment_method_id": "payment-method-uuid",
"note": "Paid in cash on delivery",
"reference_number": "REF-12345",
"date": "2026-04-15T18:00:00"
}| Field | Type | Required | Description |
|---|---|---|---|
amount | number | Yes | Payment amount (0.01 to remaining unpaid) |
payment_method_id | uuid | Yes | UUID of a payment method enabled for this tenant |
note | string | No | Free-text note |
reference_number | string | No | External reference (e.g. bank transfer id) |
date | datetime | No | Payment date (defaults to now) |
Response (201)
{
"data": {
"id": "uuid",
"transaction_no": "TRX-0043",
"amount": "100.00",
"currency": "SAR",
"status": "confirmed",
"is_deposit": false,
"note": "Paid in cash on delivery",
"date": "2026-04-15T18:00:00.000000Z",
"payment_method": { "id": "uuid", "name": "Cash", "slug": "on_arrival" },
"order": { "id": "uuid", "order_number": "ORD-001" },
"created_at": "2026-04-15T18:00:00.000000Z",
"updated_at": "2026-04-15T18:00:00.000000Z"
}
}422 invalid_order_status if the order is in draft; 422 order_fully_paid if the remaining unpaid amount is already 0.Webhooks
Webhooks allow your application to receive real-time notifications when order events occur.
Maximum 3 webhooks per tenant. All payloads are signed with HMAC-SHA256.
Available events:
order.createdorder.updatedorder.deletedorder.status_changedorder.invoice_createdorder.payment_accepted/webhookswebhooks:writeRegister a new webhook endpoint. The secret is only returned once at creation.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS endpoint to receive payloads |
events | string[] | Yes | Event names to subscribe to |
Response
{
"data": {
"id": "uuid",
"url": "https://your-app.com/webhooks/mahjoz",
"events": ["order.created", "order.status_changed"],
"is_active": true,
"secret": "a1b2c3...64_char_secret",
"last_triggered_at": null,
"created_at": "2026-04-13T19:00:00.000000Z",
"updated_at": "2026-04-13T19:00:00.000000Z"
}
}/webhookswebhooks:readList all webhooks registered by the authenticated client.
Response
{
"data": [
{
"id": "uuid",
"url": "https://your-app.com/webhooks/mahjoz",
"events": ["order.created", "order.status_changed"],
"is_active": true,
"last_triggered_at": "2026-04-13T20:30:00.000000Z",
"created_at": "2026-04-13T19:00:00.000000Z",
"updated_at": "2026-04-13T19:00:00.000000Z"
}
]
}/webhooks/{webhook_id}webhooks:readGet a specific webhook by ID.
Response
{
"data": {
"id": "uuid",
"url": "https://your-app.com/webhooks/mahjoz",
"events": ["order.created", "order.status_changed"],
"is_active": true,
"last_triggered_at": "2026-04-13T20:30:00.000000Z",
"created_at": "2026-04-13T19:00:00.000000Z",
"updated_at": "2026-04-13T19:00:00.000000Z"
}
}/webhooks/{webhook_id}webhooks:writeUpdate a webhook's URL, events, or active status.
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | New HTTPS endpoint |
events | string[] | No | New event subscriptions |
is_active | boolean | No | Enable or disable the webhook |
Response
{
"data": {
"id": "uuid",
"url": "https://your-app.com/webhooks/mahjoz",
"events": ["order.created", "order.updated"],
"is_active": false,
"last_triggered_at": "2026-04-13T20:30:00.000000Z",
"created_at": "2026-04-13T19:00:00.000000Z",
"updated_at": "2026-04-13T19:15:00.000000Z"
}
}/webhooks/{webhook_id}webhooks:writeDelete a webhook. Returns 204 No Content.
Response
204 No ContentPayload Format
All webhook deliveries include a Signature header (HMAC-SHA256 of the body using your secret) and an X-Mahjoz-Event header with the event name.
Response
{
"event": "order.created",
"webhook_id": "uuid",
"timestamp": "2026-04-13T19:30:00+03:00",
"data": {
"id": "order-uuid",
"order_number": "ORD-001",
"status": "confirmed",
"customer": { "id": "uuid", "first_name": "...", "last_name": "..." },
"branch": { "id": "uuid", "name": "Main Branch" },
"items": [ ... ],
"transactions": [ ... ],
"currency": "SAR",
"total": 50.00,
"discount_amount": 0,
"tax_amount": 7.50
}
}