🏪API

Version: 2 Last Updated: October 2025

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.

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

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

# 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

{
  "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

{
  "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

GET /api/public/branches

Response

[
  {
    "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

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

Response

{
  "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

GET /api/public/products

Response

[
  {
    "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

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

Response

{
  "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)

Example Request

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

Response

{
  "items": [
    {
      "id": "3a1c11b5-3fc3-2016-1890-1a285e601de7",
      "name": "John Doe",
      "customerNumber": 123778,
      "mobileNumber": "966502493366",
      "email": "[email protected]",
      "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

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

Response

{
  "id": "3a1c11b5-3fc3-2016-1890-1a285e601de7",
  "name": "John Doe",
  "customerNumber": 123778,
  "mobileNumber": "966502493366",
  "email": "[email protected]",
  "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

{
  "name": "John Smith",
  "mobileNumber": "+966501233567",
  "email": "[email protected]",
  "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:

"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

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

Response

{
  "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)

{
  "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)

{
  "customerDetails": {
    "name": "Jane Smith",
    "mobileNumber": "+966501234567",
    "email": "[email protected]",
    "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

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

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

Temporarily pauses an active subscription.

Request Body

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

Response

{
  "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

{
  "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

{
  "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

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

Response

{
  "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

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

Response

{
  "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

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

[
  {
    "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

{
  "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)

{
  "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)

{
  "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)

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

Example: Update start date and end date

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

Example: Update all fields

{
  "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)

{
  "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)

{
  "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

{
  "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

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

Response

Status: 204 No Content

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

Cancels an existing reservation.

Headers: Content-Type: application/json

Request Body

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

Example Request

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

{
  "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: October 2025 | Version 2

Last updated