# API

> **Version:** 2 **Last Updated:** January 2026

This document describes the public API endpoints available for merchants to integrate with the platform. All endpoints follow RESTful conventions and use JSON for data exchange.

## 🚀 Quick Start

For authentication and API key management, please refer to the [Quick Start Guide](https://docs.rekaz.io/quick-start).

**Base URL:** `https://platform.rekaz.io/api/public`

### 🔑 Authentication

All API endpoints require:

* **Authorization**: Passed in `Authorization` header
* **Tenant ID**: Passed in `__tenant` header

#### Example Headers

```http
Authorization: Basic YOUR-ENCODED-AUTHORIZATION-KEY
__tenant: YOUR_TENANT_ID
Content-Type: application/json
```

***

## 📋 Attendances API

Manage customer check-ins and attendance tracking for reservations and subscriptions.

### `GET` /api/public/attendances

Retrieves a paginated list of recent customer attendances with optional filtering.

#### Query Parameters

| Parameter        | Type   | Required | Default | Description                          |
| ---------------- | ------ | -------- | ------- | ------------------------------------ |
| `customerId`     | Guid   | No       | null    | Filter by specific customer ID       |
| `mobileNumber`   | string | No       | null    | Filter by customer mobile number     |
| `customerNumber` | long   | No       | null    | Filter by customer number            |
| `skipCount`      | int    | No       | 0       | Number of records to skip            |
| `maxResultCount` | int    | No       | 100     | Maximum records to return (max: 100) |

#### Example Requests

```http
# Search by customer ID
GET /api/public/attendances?customerId=3fa85f64-5717-4562-b3fc-2c963f66afa6

# Search by mobile number
GET /api/public/attendances?mobileNumber=+966501234567

# Search by customer number
GET /api/public/attendances?customerNumber=12345

# Combined with pagination
GET /api/public/attendances?mobileNumber=+966501234567&skipCount=0&maxResultCount=20
```

#### Response

```json
{
  "items": [
    {
      "type": "CheckIn",
      "actionType": "Subscription",
      "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "customerName": "John Doe",
      "customerMobileNumber": "+966501234567",
      "providers": ["Provider A", "Provider B"],
      "customerImageUrl": "https://example.com/image.jpg",
      "actionName": "Premium Membership",
      "actionId": "7fa85f64-5717-4562-b3fc-2c963f66afa6",
      "actionDateFrom": "2025-01-15T09:00:00Z",
      "actionDateTo": "2025-01-15T10:00:00Z",
      "isActive": true,
      "canDoCheckIn": true,
      "isFirstCheckIn": false,
      "customFields": [
        {
          "label": "Membership Level",
          "value": "Gold"
        }
      ],
      "isPackage": false
    }
  ],
  "totalCount": 150
}
```

### `POST` /api/public/attendances

Records a new attendance entry for a customer action.

#### Request Body

```json
{
  "type": 1, // 0 = Reservation, 1 = Subscription
  "actionType": 0, // 0 = Check-In, 1 = Check-Out
  "customerId": "3a1c29af-6c55-0661-5e51-8403ff2b9288",
  "actionId": "3a1c29af-928e-e595-ac07-9dce32224136" // ReservationId or SubscriptionId
}
```

#### Response

Returns the created attendance record with all populated fields (same structure as GET response item).

***

## 🏢 Branches API

Manage and retrieve branch information for your merchant account.

### `GET` /api/public/branches

Retrieves all branches associated with your merchant account.

#### Example Request

```http
GET /api/public/branches
```

#### Response

```json
[
  {
    "id": "3a1bfd57-1b9d-0f99-c9d2-446b6aec5dc4",
    "name": "الفرع الرئيسي",
    "nameAr": "الفرع الرئيسي",
    "nameEn": "Main Branch",
    "addressUrl": null
  },
  {
    "id": "4b2cf47g-5e86-4251-641g-2d67ge9a8886",
    "name": "الفرع الثانوي",
    "nameAr": "الفرع الثانوي",
    "nameEn": "Secondary Branch",
    "addressUrl": "https://maps.example.com/branch2"
  }
]
```

### `GET` /api/public/branches/{id}

Retrieves a specific branch by its ID.

#### Example Request

```http
GET /api/public/branches/3a1bfd57-1b9d-0f99-c9d2-446b6aec5dc4
```

#### Response

```json
{
  "id": "3a1bfd57-1b9d-0f99-c9d2-446b6aec5dc4",
  "name": "الفرع الرئيسي",
  "nameAr": "الفرع الرئيسي",
  "nameEn": "Main Branch",
  "addressUrl": null
}
```

***

## 📦 Products API

Get all available services (referred to as products in the API).

### `GET` /api/public/products

Retrieves all products available for public consumption.

#### Example Request

```http
GET /api/public/products
```

#### Response

```json
[
  {
    "id": "bf344bc3-5b1b-4760-b23d-cf3135d437ca",
    "name": "غسيل السيارات",
    "nameAr": "غسيل السيارات",
    "nameEn": "Car Wash Service",
    "description": "",
    "shortDescription": "",
    "amount": 30,
    "duration": null,
    "slots": null,
    "productProviders": [
      {
        "id": "72bbb3ed-3160-485b-a48f-a90e909602e2",
        "image": null,
        "name": "Default Service Provider",
        "description": ""
      }
    ],
    "pricing": [
      {
        "id": "3a1bf3a6-8d25-4a0d-16b6-069be6c0f248",
        "name": "سيارة صغيرة",
        "nameAr": "سيارة صغيرة",
        "nameEn": "Small Car",
        "model": 0,
        "billingCycle": 0,
        "amount": 30,
        "discountedAmount": 30,
        "hasMinimum": false,
        "hasDeposit": false,
        "hasOccurrence": false,
        "duration": null,
        "sku": null
      }
    ],
    "maximumQuantityPerOrder": 1,
    "customFields": [
      {
        "id": "3a1bf3a4-2f9f-e479-bcd9-7835d99eaf04",
        "name": "location_field",
        "label": "Wash Location",
        "placeholder": "Choose your location",
        "showInCheckout": true,
        "amount": 0
      }
    ],
    "type": 0,
    "typeString": "Reservation",
    "branchIds": ["3a1bf36f-4d75-3140-530f-1c56fd89e775"]
  }
]
```

### `GET` /api/public/products/{id}

Retrieves a specific product by its ID.

#### Example Request

```http
GET /api/public/products/bf344bc3-5b1b-4760-b23d-cf3135d437ca
```

#### Response

```json
{
  "id": "bf344bc3-5b1b-4760-b23d-cf3135d437ca",
  "name": "غسيل السيارات",
  "nameAr": "غسيل السيارات",
  "nameEn": "Car Wash Service",
  "description": "",
  "shortDescription": "",
  "amount": 30,
  "duration": null,
  "slots": null,
  "productProviders": [
    {
      "id": "72bbb3ed-3160-485b-a48f-a90e909602e2",
      "image": null,
      "name": "Default Service Provider",
      "description": ""
    }
  ],
  "pricing": [
    {
      "id": "3a1bf3a6-8d25-4a0d-16b6-069be6c0f248",
      "name": "سيارة صغيرة",
      "nameAr": "سيارة صغيرة",
      "nameEn": "Small Car",
      "model": 0,
      "billingCycle": 0,
      "amount": 30,
      "discountedAmount": 30,
      "hasMinimum": false,
      "hasDeposit": false,
      "hasOccurrence": false,
      "duration": null,
      "sku": null
    }
  ],
  "maximumQuantityPerOrder": 1,
  "customFields": [
    {
      "id": "3a1bf3a4-2f9f-e479-bcd9-7835d99eaf04",
      "name": "location_field",
      "label": "Wash Location",
      "placeholder": "Choose your location",
      "showInCheckout": true,
      "amount": 0
    }
  ],
  "type": 0,
  "typeString": "Reservation",
  "branchIds": ["3a1bf36f-4d75-3140-530f-1c56fd89e775"]
}
```

***

## 👥 Customers API

Get all your customers.

### `GET` /api/public/customers

Retrieves all customers.

#### Query Parameters

| Parameter        | Type   | Required | Default | Description                                      |
| ---------------- | ------ | -------- | ------- | ------------------------------------------------ |
| `skipCount`      | int    | No       | 0       | Number of records to skip (for pagination)       |
| `maxResultCount` | int    | No       | 100     | Maximum records to return (max: 100)             |
| `mobileNumber`   | string | No       | -       | Filter customers by mobile number (e.g. +966...) |

#### Example Request

```http
GET /api/public/customers?skipCount=0&maxResultCount=20
```

#### Example Request (Filter by Mobile Number)

```http
GET /api/public/customers?mobileNumber=+966501234567
```

#### Response

```json
{
  "items": [
    {
      "id": "3a1c11b5-3fc3-2016-1890-1a285e601de7",
      "name": "John Doe",
      "customerNumber": 123778,
      "mobileNumber": "966502493366",
      "email": "john@example.com",
      "customerType": 1,
      "address": null,
      "companyName": null,
      "customFields": {},
      "branchIds": ["3a1bfd57-1b9d-0f99-c9d2-446b6aec5dc4"],
      "isBlocked": false
    }
  ],
  "totalCount": 13
}
```

### `GET` /api/public/customers/{id}

Get a specific customer by ID.

#### Example Request

```http
GET /api/public/customers/3a1bf3b5-b54f-34c7-db92-5ff28ff22315
```

#### Response

```json
{
  "id": "3a1c11b5-3fc3-2016-1890-1a285e601de7",
  "name": "John Doe",
  "customerNumber": 123778,
  "mobileNumber": "966502493366",
  "email": "john@example.com",
  "customerType": 1,
  "address": null,
  "companyName": null,
  "customFields": {},
  "branchIds": ["3a1bfd57-1b9d-0f99-c9d2-446b6aec5dc4"],
  "isBlocked": false
}
```

### `POST` /api/public/customers

Creates a new customer record in the system.

#### Request Body

```json
{
  "name": "John Smith",
  "mobileNumber": "+966501233567",
  "email": "john.smith@example.com",
  "address": "123 Main Street, Riyadh",
  "type": 1, // 1 = Individual, 2 = Company
  "branchId": "3a1bf36f-4d75-3140-530f-1c56fd89e775",
  "companyName": "ABC Company Ltd",
  "customFields": {
    "field1": "value1",
    "field2": "value2"
  }
}
```

#### Response

Returns the created customer ID:

```json
"3a1bf3d6-1c84-d69e-e2d5-eb6b4f08f6d8"
```

***

## 📅 Subscriptions API

Manage recurring subscription services for customers.

### `GET` /api/public/subscriptions

Retrieves a paginated list of customer subscriptions with custom field support.

#### Query Parameters

| Parameter        | Type     | Required | Description                                   |
| ---------------- | -------- | -------- | --------------------------------------------- |
| `skipCount`      | int      | No       | Number of records to skip (for pagination)    |
| `maxResultCount` | int      | No       | Maximum records to return (max: 100)          |
| `customerId`     | Guid     | No       | Filter by specific customer ID                |
| `customerMobile` | string   | No       | Filter by customer mobile number              |
| `startAtMin`     | datetime | No       | Filter subscriptions starting from this date  |
| `startAtMax`     | datetime | No       | Filter subscriptions starting until this date |
| `statuses`       | array    | No       | Filter by statuses (e.g., "Active", "Paused") |
| `branchId`       | Guid     | No       | Filter by branch ID                           |
| `keyword`        | string   | No       | Search keyword across subscription details    |

#### Example Request

```http
GET /api/public/subscriptions?customerId=7fa85f64-5717-4562-b3fc-2c963f66afa6&skipCount=0&maxResultCount=20
```

#### Response

```json
{
  "totalCount": 45,
  "items": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "customerId": "7fa85f64-5717-4562-b3fc-2c963f66afa6",
      "startAt": "2025-01-01T00:00:00Z",
      "endAt": "2025-02-01T00:00:00Z",
      "status": "Active",
      "items": [
        {
          "id": "8fa85f64-5717-4562-b3fc-2c963f66afa6",
          "priceId": "9fa85f64-5717-4562-b3fc-2c963f66afa6",
          "name": "Monthly Gym Access",
          "productName": "Gym Membership",
          "quantity": 1,
          "billingCycle": "Monthly"
        }
      ],
      "discount": {
        "type": "Percentage",
        "value": 10
      },
      "branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "occurenceDays": ["Monday", "Wednesday", "Friday"],
      "customFields": [
        {
          "name": "trainer_assigned",
          "label": "Personal Trainer",
          "type": "String",
          "value": "Mike Johnson"
        }
      ],
      "paidAmount": 500.0,
      "totalAmount": 500.0,
      "remainingAmount": 0.0,
      "lastInvoiceCode": "INV-2025-001",
      "lastInvoiceStatus": "Paid",
      "isPaused": false,
      "pausedAt": null,
      "resumeAt": null
    }
  ]
}
```

### `GET` /api/public/subscriptions/{id}

Returns detailed information about a specific subscription.

### `POST` /api/public/subscriptions

Creates a new subscription, optionally creating a new customer.

#### Request Body (Existing Customer)

```json
{
  "customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "startAt": "2025-02-01T00:00:00Z",
  "discount": {
    "type": "Fixed",
    "value": 50
  },
  "branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "items": [
    {
      "priceId": "9fa85f64-5717-4562-b3fc-2c963f66afa6",
      "quantity": 1
    }
  ],
  "occurenceDays": ["Monday", "Wednesday", "Friday"]
}
```

#### Request Body (New Customer)

```json
{
  "customerDetails": {
    "name": "Jane Smith",
    "mobileNumber": "+966501234567",
    "email": "jane.smith@example.com",
    "type": 1, // 1 = Individual, 2 = Company
    "companyName": ""
  },
  "branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "startAt": "2025-02-01T00:00:00Z",
  "items": [
    {
      "priceId": "9fa85f64-5717-4562-b3fc-2c963f66afa6",
      "quantity": 1
    }
  ]
}
```

#### Response

```json
{
  "invoiceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
```

### `PUT` /api/public/subscriptions/{id}/dates

Updates the subscription's start date and/or next billing date without altering other attributes.

#### Request Body

* `startAt` (datetime, optional): Subscription start date in ISO 8601 format.
* `endAt` (datetime, optional): Next billing date (next charge) in ISO 8601 format.
* At least one of `startAt` or `endAt` must be provided in the request payload.

#### Sample Bodies

1. **Update both dates**

```json
{
  "startAt": "2025-02-01T00:00:00Z",
  "endAt": "2025-05-01T00:00:00Z"
}
```

2. **Update only start date**

```json
{
  "startAt": "2025-02-01T00:00:00Z"
}
```

3. **Update only end date**

```json
{
  "endAt": "2025-05-01T00:00:00Z"
}
```

### `POST` /api/public/subscriptions/{id}/pause

Temporarily pauses an active subscription.

#### Request Body

```json
{
  "pausedAt": "2025-01-20T00:00:00Z",
  "resumeAt": "2025-02-01T00:00:00Z"
}
```

#### Response

```json
{
  "subscriptionId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "pausedAt": "2025-01-20T00:00:00Z",
  "resumeAt": "2025-02-01T00:00:00Z"
}
```

### `POST` /api/public/subscriptions/{id}/resume

Resumes a paused subscription.

#### Request Body

```json
{
  "resumeAt": "2025-01-25T00:00:00Z"
}
```

#### Response

Returns the full subscription object with updated status.

***

## 🧑‍💼 Providers

### `GET` /api/public/providers

Retrieves all available providers.

#### Response

```json
{
  "items": [
    {
      "id": "a1b2c3d4-5678-90ab-cdef-1234567890ab",
      "name": "Dr. Ahmed Ali"
    },
    {
      "id": "b2c3d4e5-6789-01bc-def0-234567890bcd",
      "name": "Sara Mohammed"
    }
  ]
}
```

***

## 🎯 Reservations API

Manage time-based bookings and appointments with availability checking.

### `GET` /api/public/reservations

Retrieves a paginated list of reservations with custom field support.

#### Query Parameters

| Parameter        | Type     | Required | Description                                |
| ---------------- | -------- | -------- | ------------------------------------------ |
| `skipCount`      | int      | No       | Number of records to skip (for pagination) |
| `maxResultCount` | int      | No       | Maximum records to return (max: 100)       |
| `dateMin`        | datetime | No       | Filter reservations from this date         |
| `dateMax`        | datetime | No       | Filter reservations until this date        |
| `statuses`       | array    | No       | Filter by statuses (e.g., "Confirmed")     |
| `customerId`     | Guid     | No       | Filter by specific customer ID             |
| `customerMobile` | string   | No       | Filter by customer mobile number           |
| `upcoming`       | boolean  | No       | Filter for upcoming reservations           |
| `keyword`        | string   | No       | Search keyword across reservation details  |
| `branchId`       | Guid     | No       | Filter by branch ID                        |

#### Example Request

```http
GET /api/public/reservations?customerId=7fa85f64-5717-4562-b3fc-2c963f66afa6&upcoming=true
```

#### Response

```json
{
  "totalCount": 89,
  "items": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "startAt": "2025-01-20T14:00:00Z",
      "endAt": "2025-01-20T15:00:00Z",
      "status": "Confirmed",
      "customStatus": "VIP",
      "customerName": "John Doe",
      "customerMobile": "+966501234567",
      "customerId": "7fa85f64-5717-4562-b3fc-2c963f66afa6",
      "reservationNumber": 10234,
      "productName": "Tennis Court",
      "priceName": "Peak Hours",
      "quantity": 1,
      "providers": ["Court A"],
      "customFields": [
        {
          "name": "equipment_needed",
          "label": "Equipment Required",
          "type": "Boolean",
          "value": true
        }
      ],
      "invoiceTotalAmount": 150.0,
      "reservationTotalAmount": 150.0,
      "reservationRemainingAmount": 0.0,
      "branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "branchName": "Main Branch",
      "meetingUrl": "https://meet.example.com/abc123",
      "source": "WebBooking",
      "isZeroPrice": false,
      "isWalkInCustomer": false
    }
  ]
}
```

> **Note:** The remaining amount field is now named `reservationRemainingAmount` for consistency with other reservation amount fields.

### `GET` /api/public/reservations/{id}

Retrieves a specific reservation by its ID.

#### Example Request

```http
GET /api/public/reservations/3fa85f64-5717-4562-b3fc-2c963f66afa6
```

#### Response

```json
{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "startAt": "2025-01-20T14:00:00Z",
  "endAt": "2025-01-20T15:00:00Z",
  "status": "Confirmed",
  "customStatus": "VIP",
  "customerName": "John Doe",
  "customerMobile": "+966501234567",
  "customerId": "7fa85f64-5717-4562-b3fc-2c963f66afa6",
  "reservationNumber": 10234,
  "productName": "Tennis Court",
  "priceName": "Peak Hours",
  "quantity": 1,
  "providers": ["Court A"],
  "customFields": [
    {
      "name": "equipment_needed",
      "label": "Equipment Required",
      "type": "Boolean",
      "value": true
    }
  ],
  "invoiceTotalAmount": 150.0,
  "reservationTotalAmount": 150.0,
  "reservationRemainingAmount": 0.0,
  "branchId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "branchName": "Main Branch",
  "meetingUrl": "https://meet.example.com/abc123",
  "source": "WebBooking",
  "isZeroPrice": false,
  "isWalkInCustomer": false
}
```

### `GET` /api/public/reservations/slots

Retrieves available time slots for reservations.

#### Query Parameters

| Parameter           | Type     | Required | Description                                                                 |
| ------------------- | -------- | -------- | --------------------------------------------------------------------------- |
| `StartDate`         | datetime | Yes      | **Your desired start date** for slot search (format: `2025-08-10T20:00:00`) |
| `EndDate`           | datetime | Yes      | **Your desired end date** for slot search (format: `2025-08-25T21:00:00`)   |
| `PriceId`           | Guid     | Yes      | Price configuration ID from products                                        |
| `MinQuantity`       | int      | Yes      | Minimum quantity required (must be ≥ 1)                                     |
| `MinProvidersCount` | int      | No       | Minimum number of providers required                                        |
| `ProvidersIds`      | Guid\[]  | No       | Specific provider IDs to filter by                                          |

#### Example Request

```http
GET /api/public/reservations/slots?StartDate=2025-08-10T20:00:00&EndDate=2025-08-25T21:00:00&PriceId=3a1c12e6-c66b-6ac5-90a7-8b791791af3c&MinQuantity=1&MinProvidersCount=1
```

**How to set dates:**

* `StartDate`: When you want to start looking for available slots (e.g., today or tomorrow)
* `EndDate`: How far ahead you want to search (e.g., next week or month)

**Common Issues:**

* Ensure `MinQuantity` is at least 1 (required validation)
* DateTime format should be `YYYY-MM-DDTHH:mm:ss` (without timezone)
* `PriceId` must be a valid GUID from the products endpoint

#### Response

```json
[
  {
    "from": "2025-09-09T06:00:00Z",
    "to": "2025-10-12T06:00:00Z",
    "availableReservationsCount": 1,
    "availableProvidersCount": 0,
    "availableProviderIds": [],
    "isOutDated": false,
    "isAvailable": false,
    "amounts": {
      "totalPrice": 382.95,
      "effectiveQuantity": 1,
      "totalAfterDiscount": 382.95,
      "depositAmount": null
    },
    "maxConnectedTo": "2025-10-12T06:00:00Z",
    "allProvidersAvailability": {
      "45bb3834-9869-4d12-83af-fa347448aa60": false
    }
  }
]
```

### `PUT` /api/public/reservations/{id}

Updates an existing reservation's start date, end date, and/or assigned providers.

#### Request Body

```json
{
  "startDate": "2025-01-20T14:00:00Z",
  "endDate": "2025-01-20T15:00:00Z",
  "providerIds": ["3fa85f64-5717-4562-b3fc-2c963f66afa6"]
}
```

**Parameters:**

* `startDate` (required, DateTime): The start date and time for the reservation in ISO 8601 format. **This field is required in the request, but you can pass the existing start date if you only want to update the end date or providers**
* `endDate` (optional, DateTime): The new end date and time for the reservation in ISO 8601 format. **If not provided, the system automatically preserves the original reservation duration.** For example, if the original reservation was 1 hour long, the updated reservation will also be 1 hour long starting from the new `startDate`
* `providerIds` (optional, array of GUID): List of provider IDs to assign to the reservation. **If not provided, the existing providers will be kept**

> **Note:** `startDate` is required in every request. `endDate` and `providerIds` are optional and will retain their existing values if not included. To update only the end date or providers without changing the start date, include the current start date in the request.
>
> **Duration Preservation:** When you update the `startDate` without providing an `endDate`, the system automatically calculates the new `endDate` by preserving the original reservation duration. This ensures the reservation length remains consistent.

**Example: Update only the start date (duration is preserved)**

```json
{
  "startDate": "2025-10-16T10:00:00Z"
}
```

*If the original reservation was from 14:00 to 15:00 (1 hour), the updated reservation will be from 10:00 to 11:00 (still 1 hour).*

**Example: Update only the end date (keeping start date the same)**

```json
{
  "startDate": "2025-01-20T14:00:00Z", // Current/existing start date
  "endDate": "2025-01-20T16:00:00Z" // New end date
}
```

**Example: Update only the providers (keeping dates the same)**

```json
{
  "startDate": "2025-01-20T14:00:00Z", // Current/existing start date
  "providerIds": ["b2c3d4e5-6789-01bc-def0-234567890bcd"]
}
```

**Example: Update start date and end date**

```json
{
  "startDate": "2025-10-16T10:00:00Z",
  "endDate": "2025-10-16T11:00:00Z"
}
```

**Example: Update all fields**

```json
{
  "startDate": "2025-10-16T10:00:00Z",
  "endDate": "2025-10-16T11:00:00Z",
  "providerIds": ["b2c3d4e5-6789-01bc-def0-234567890bcd"]
}
```

#### Response

Returns `204 No Content` on success.

### `POST` /api/public/reservations/bulk

Creates multiple reservations in a single request.

#### Request Body (Existing Customer)

```json
{
  "customerId": "3a1c2245-564d-84ec-af57-c7b85af1441f",
  "branchId": "3a1c1320-ef97-fa70-ddb6-15ad0832397f",
  "items": [
    {
      "quantity": 1,
      "priceId": "3a1c2281-1154-f9d2-f96f-210b7021eedb",
      "from": "2025-09-04T17:00:00Z",
      "to": "2025-09-04T18:00:00Z",
      "providerIds": [],
      "customFields": {},
      "discount": {
        "type": "percentage",
        "value": 0
      }
    }
  ]
}
```

#### Request Body (New Customer)

```json
{
  "customerDetails": {
    "name": "Final Test",
    "mobileNumber": "+966502203642",
    "email": "",
    "type": 1,
    "companyName": ""
  },
  "branchId": "3a1c1320-ef97-fa70-ddb6-15ad0832397f",
  "items": [
    {
      "quantity": 1,
      "priceId": "3a1c2281-1154-f9d2-f96f-210b7021eedb",
      "from": "2025-09-04T17:00:00Z",
      "to": "2025-09-04T18:00:00Z",
      "providerIds": [],
      "customFields": {},
      "discount": {
        "type": "percentage",
        "value": 0
      }
    }
  ]
}
```

#### Response

```json
{
  "invoiceId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "reservationIds": ["4fa85f64-5717-4562-b3fc-2c963f66afa6"],
  "paymentLink": "https://platform.rekaz.io/i/NcRo"
}
```

### `PUT` /api/public/reservations/{id}/confirm

Confirms a pending reservation.

#### Example Request

```http
PUT /api/public/reservations/3fa85f64-5717-4562-b3fc-2c963f66afa6/confirm
```

#### Response

Status: `204 No Content`

### `PUT` /api/public/reservations/{id}/done

Marks a reservation as completed (done).

#### Example Request

```http
PUT /api/public/reservations/3fa85f64-5717-4562-b3fc-2c963f66afa6/done
```

#### Response

Status: `204 No Content`

### `PUT` /api/public/reservations/{id}/cancel

Cancels an existing reservation.

Headers: `Content-Type: application/json`

#### Request Body

```json
{
  "cancellationReason": "Customer requested cancellation",
  "notifyCustomer": true
}
```

#### Example Request

```http
PUT /api/public/reservations/3fa85f64-5717-4562-b3fc-2c963f66afa6/cancel
```

#### Response

Status: `204 No Content`

***

## ⚠️ Error Handling

All endpoints follow standard HTTP status codes and return consistent error responses.

### Error Response Format

```json
{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "The request validation failed",
    "details": "The mobile number format is invalid",
    "validationErrors": [
      {
        "field": "mobileNumber",
        "message": "Must be a valid Saudi mobile number"
      }
    ]
  }
}
```

### HTTP Status Codes

| Status Code | Description                                  |
| ----------- | -------------------------------------------- |
| 200         | Success                                      |
| 201         | Created successfully                         |
| 204         | No Content                                   |
| 400         | Bad request - validation error               |
| 401         | Unauthorized - invalid API key               |
| 403         | Forbidden - missing branch ID or permissions |
| 404         | Resource not found                           |
| 500         | Internal server error                        |

***

### Common Error Codes

| Error Code           | Description                       |
| -------------------- | --------------------------------- |
| `ValidationError`    | Request data validation failed    |
| `NotFound`           | Requested resource does not exist |
| `Unauthorized`       | Invalid or missing authentication |
| `RateLimit`          | Too many requests                 |
| `BusinessLogicError` | Business rule violation           |

***

***

*Last updated: January 2026 | Version 2*


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rekaz.io/merchant-public-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
