Authentication
Every request must include an x-api-key header. The value is matched against a server-side environment variable. Requests with a missing or incorrect key receive a 401 response immediately, before any business logic runs.
| Header | Type | Required | Description |
|---|---|---|---|
| x-api-key | string | required | Your assigned API key. Validated server-side against an environment variable. |
| Content-Type | string | required | Must be application/json for all POST requests. |
Customer Signup
Registers a new customer using a two-step OTP verification flow. The same endpoint URL handles both steps — the presence or absence of the otp field in the request body determines which step is executed.
otp. Server sends a 4-digit code via SMS or WhatsApp.otp added. Returns login token and customer record.+971) and KSA (+966) numbers receive the OTP via SMS. All other country codes receive it via WhatsApp. The OTP expires after 5 minutes and is single-use.
Validates the supplied customer details, checks for duplicate mobile/email, generates a 4-digit OTP, and delivers it via SMS (UAE/KSA) or WhatsApp (all other regions). Returns step: "otp_sent" on success.
| Parameter | Type | Required | Description |
|---|---|---|---|
| mobileNumber | string | required | Mobile number in E.164 format without the leading +. Examples: 971501234567 (UAE), 966501234567 (KSA). |
| first_name | string | required | Customer's first name. |
| last_name | string | required | Customer's last name. |
| branch_id | integer | required | ID of the branch the customer is registering at. |
| string | optional | Valid email address. Returns 400 if format is invalid; 409 if already registered. | |
| birthdate | string | optional | Date of birth in YYYY-MM-DD format. Returns 400 if format is invalid. |
| gender | string | optional | One of: male, female, other. Returns 400 for any other value. |
| country_id | integer | optional | Country reference ID from the platform's country table. |
| brand_id | integer | optional | Brand reference ID for multi-brand deployments. |
Re-submit the Step 1 body with the otp field added. The server validates the OTP (checks it is not expired, not previously used, and matches the stored code), then creates the customer record with customer_level: WHITE, creates a loyalty wallet, and generates a referral code. Returns a login token and the full customer object.
| Parameter | Type | Required | Description |
|---|---|---|---|
| mobileNumber | string | required | Must match the number used in Step 1 exactly. |
| otp | string | required | The 4-digit OTP received by the customer. Returns 400 if expired, already used, or incorrect. |
| first_name, last_name, branch_id | — | required | Same values as Step 1. Re-validated on submission. |
| email, birthdate, gender, country_id, brand_id | — | optional | Same optional fields as Step 1. Include them if they were part of the Step 1 payload. |
Error Reference
| Status | Code / Condition | Description |
|---|---|---|
| 400 | missing_fields | One or more required fields (mobileNumber, first_name, last_name, branch_id) are absent from the request body. |
| 400 | invalid_email | The email field is present but is not a valid email address format. |
| 400 | invalid_birthdate | The birthdate field is present but does not match YYYY-MM-DD format. |
| 400 | invalid_gender | The gender field is present but is not one of male, female, or other. |
| 400 | otp_invalid | The supplied OTP does not match the stored code for this mobile number. |
| 400 | otp_expired | The OTP was generated more than 5 minutes ago and is no longer valid. Restart from Step 1. |
| 400 | otp_already_used | This OTP has already been successfully verified once. Restart from Step 1. |
| 401 | unauthorized | The x-api-key header is missing or does not match the server-side value. |
| 409 | mobile_exists | A customer with this mobile number is already registered. Direct the user to login instead. |
| 409 | email_exists | A customer with this email address is already registered. |
| 503 | delivery_failure | The SMS or WhatsApp provider was unable to deliver the OTP. Retry after a short delay; if persistent, check the number format. |
| 500 | internal_error | An unexpected server-side error occurred. Contact the platform team with the request ID if available. |
Integration Notes
+. For example, a UAE number would be 971501234567 rather than +971501234567 or 0501234567.Get Member Details
Looks up a customer record by phone number within a specific branch's loyalty club. Requires three request headers in addition to the body — all three are validated before any lookup is performed.
Returns full membership details for a customer matched by their phone number within the specified branch club. The phone number is normalised through validateAndFormat() before the lookup — submitting a malformed number returns a 400 before any DB query runs.
| Header | Type | Required | Description |
|---|---|---|---|
| x-api-key | string | required | Must match the API_KEY server environment variable. Returns 401 if absent or incorrect. |
| x-branch-id | string | required | The branch's club_id (string identifier, not the numeric branch row ID). Returns 400 if missing or if the value doesn't match any branch's club_id. |
| x-source-type | string | required | Must be the exact string "source-type". Any other value returns 400. |
| Content-Type | string | required | Must be application/json. |
| Field | Type | Required | Description |
|---|---|---|---|
| customer | object | required | Wrapper object. Returns 400 if absent or not an object. |
| customer.phoneNumber | string | required | Customer's phone number in E.164 format (e.g. +971501234567). Passed through validateAndFormat() — returns 400 if the number is invalid or unrecognised. |
+ (standard E.164). Example: +971501234567, not 971501234567.Response Field Reference
| Field | Type | Description |
|---|---|---|
| membership.firstName | string | Customer's first name. |
| membership.lastName | string | Customer's last name. |
| membership.email | string | Customer's email address. |
| membership.gender | string | One of: male, female, other. |
| membership.phoneNumber | string | Normalised E.164 phone number as stored. |
| membership.status | string | Membership status, e.g. Active. |
| membership.createdOn | string (ISO 8601) | UTC timestamp of when the membership was created. |
| membership.memberId | string | Unique membership identifier. |
| membership.mobileAppUsed | boolean | true if the customer has logged in via the mobile app. |
| membership.mobileAppUsedLastDate | string | null | ISO 8601 timestamp of last mobile app login, or null if never used. |
| membership.birthday | string (YYYY-MM-DD) | Conditionally included. Only present in the response if a birthdate is on record for this customer. Omitted entirely if not set. |
| membership.pointsBalance.balance.monetary | number | Monetary points balance (decimal). |
| membership.pointsBalance.balance.nonMonetary | integer | Non-monetary points balance (whole number). |
Error Reference
| Status | Condition | Description |
|---|---|---|
| 400 | missing x-branch-id | The x-branch-id header was not included in the request. |
| 400 | invalid x-branch-id | The x-branch-id value does not match any branch's club_id. Note: this is the club identifier string, not the numeric branch row ID. |
| 400 | invalid x-source-type | x-source-type is present but is not exactly the string "source-type". The value is matched literally. |
| 400 | missing customer object | The request body does not contain a customer object. |
| 400 | missing phoneNumber | The customer object is present but phoneNumber is absent. |
| 400 | invalid phone number | The phoneNumber value failed validateAndFormat() — the number is not a recognised or properly formatted E.164 number. |
| 401 | unauthorized | The x-api-key header is missing or does not match the server-side API_KEY environment variable. |
| 404 | member not found | No customer record exists for the given phone number within the specified branch club. |
Reservations
Returns a paginated, filterable list of reservations. No authentication required. Each item in data[] is a fully joined reservation object including customer, brand, branch (with country), section, tables, and payments. The response also echoes back a filters_applied summary of all active filter values.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| reservation_status | string | optional | — | Filter by reservation status. Accepts comma-separated values e.g. CONFIRMED,PENDING. |
| status | string | optional | — | Alias for reservation_status. Behaves identically. |
| payment_status | string | optional | PAID,PAYLATER | Filter by payment status. Accepts comma-separated values e.g. PAID,PAYLATER,REFUNDED. If omitted, defaults to PAID,PAYLATER only. |
| branch_id | number | optional | — | Filter by a specific branch. |
| brand_id | number | optional | — | Filter by brand. |
| country_id | number | optional | — | Filter by the branch's country ID. |
| country | string | optional | — | Filter by country string field on the reservation record. |
| reservation_id | string | optional | — | Exact match on the string reservation ID e.g. RES123. |
| date | ISO date | optional | — | Filters the full calendar day by start_time. Takes priority over start_date, end_date, start_time, and end_time — all four are ignored when date is present. |
| start_date | ISO date | optional | — | Range start date. Only used when date is not provided. |
| end_date | ISO date | optional | — | Range end date. Only used when date is not provided. |
| start_time | ISO datetime | optional | — | Fine-grained datetime filter. Only applied when date is absent. |
| end_time | ISO datetime | optional | — | Fine-grained datetime filter. Only applied when date is absent. |
| search | string | optional | — | Case-insensitive search across mobile_number, reservation_id, first_name, and last_name. |
| sort_by | string | optional | created_date | Any reservation field name to sort by. |
| sort_order | ASC | DESC | optional | DESC | Sort direction. |
| page | number | optional | 1 | Page number for pagination. |
| limit | number | optional | 10 | Records per page. |
payment_status is omitted entirely, the API automatically restricts results to PAID and PAYLATER records. To include other statuses such as REFUNDED or PENDING, pass them explicitly.
date is provided, the server filters the entire calendar day by start_time and completely ignores start_date, end_date, start_time, and end_time. Use start_date + end_date (or the time variants) only when date is absent.
reservation_status and payment_status accept multiple comma-separated values in a single parameter. Examples:reservation_status=CONFIRMED,PENDING
payment_status=PAID,PAYLATER,REFUNDED
Waiting List
Returns waiting list entries for a branch, with joined customer, branch (including country and brand), and table data. When id is supplied, returns a single entry object directly instead of a paginated list. No authentication required.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| id | number | optional | — | Fetch a single entry by its numeric ID. When present, all pagination and filter params are ignored. Returns 404 if not found. |
| branch_id | number | string | optional | — | Filter by branch. Accepts either the numeric branch ID or the branch code string (e.g. DT01). Both are resolved server-side. |
| brand_id | number | optional | — | Filter by brand. |
| status | string | optional | — | Filter by entry status. Known values: WAITING, READY, EXPIRED. |
| customer_id | number | optional | — | Filter by customer ID directly. |
| mobile_number | string | optional | — | Looks up the customer by mobile number first, then filters by their customer_id. If no customer is found for that number, an empty list is returned immediately. |
| date | ISO date | optional | — | Filters by createdAt — matches the full calendar day for the given date. |
| sort_by | string | optional | createdAt | Field to sort by. Allowed values: id, createdAt, updatedAt, status, party_size. |
| sort_order | asc | desc | optional | desc | Sort direction. |
| page | number | optional | 1 | Page number. |
| limit | number | optional | 10 (max 100) | Records per page. Maximum allowed value is 100. |
mobile_number is provided, the server first looks up the customer record by that number and then filters waiting list entries by the resolved customer_id. If no customer exists for that number, an empty data array is returned immediately — no error is thrown.
5) or the string branch code (e.g. DT01). The server resolves both to the same branch record.
id is present, all other filter and pagination parameters are ignored. The response shape changes: data becomes a single object (not an array), and total, page, pages, and meta are omitted.
Gift Cards
A single endpoint with six distinct modes, selected by which query parameters are present. Modes are evaluated in strict priority order — the first matching mode wins and all others are ignored. No authentication required.
1. id → 2. regular_gift_card_id → 3. bulk_table=true → 4. batch_id → 5. balance=true + card_number → 6. default list
All six modes share this URL. The response shape — and whether a JSON body or a CSV file stream is returned — is determined entirely by which query parameters are supplied. All results are sorted by created_at DESC.
Fetches a single gift card record by its numeric row ID. Returns a single object under data, not an array. Triggers 404 if no card exists with that ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | number | required | Numeric row ID of the gift card (e.g. 4513). |
Returns a paginated list of gift cards generated from a specific regular gift card template.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| regular_gift_card_id | number | required | — | ID of the gift card template. |
| page | number | optional | 1 | Page number. |
| limit | number | optional | 10 | Records per page. |
Returns a paginated list of bulk gift card batches — one row per batch, showing its ID, batch reference, name, and total card count. Does not return individual cards.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| bulk_table | boolean | required | — | Must be true to trigger this mode. |
| page | number | optional | 1 | Page number. |
| limit | number | optional | 10 | Records per page. |
Returns a single batch object including its metadata and up to 100 gift card records, sorted latest first. Returns 404 if the batch_id string does not match any batch.
| Parameter | Type | Required | Description |
|---|---|---|---|
| batch_id | string | required | Batch reference string (e.g. BATCH-001). Must not include download_csv=true to stay in this mode. |
Streams the gift cards in a batch as a downloadable CSV file. The response body is a raw file stream — not JSON. download_csv=true only works alongside batch_id; without it, the parameter is ignored.
| Parameter | Type | Required | Description |
|---|---|---|---|
| batch_id | string | required | Batch reference string. |
| download_csv | boolean | required | Must be true. Switches the response to a CSV file stream. |
Looks up a single card by its card number and returns its current balance, currency, and status. Returns 404 if no card exists with that number.
| Parameter | Type | Required | Description |
|---|---|---|---|
| balance | boolean | required | Must be true to trigger balance check mode. |
| card_number | string | required | The gift card number to check (e.g. 1521543829). |
The default mode — triggered when none of the special params above are present. Returns a paginated list of gift cards across all types. All filters are optional. Results sorted by created_at DESC.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| branch_id | number | optional | — | Filter by branch. |
| brand_id | number | optional | — | Filter by brand. |
| customer_id | number | optional | — | Filter by customer. |
| card_number | string | optional | — | Exact match on card number. |
| status | string | optional | — | Filter by status. Accepted values: active, inactive. |
| mobile_number | string | optional | — | Resolves to a customer via the transaction table. Returns empty list immediately if no transactions found for that number. |
| bulk_gift_card_id | number | optional | — | Returns only unpurchased cards belonging to this bulk batch ID. Returns 400 if value is non-numeric. |
| page | number | optional | 1 | Page number. |
| limit | number | optional | 10 | Records per page. |
| Field | Type | Description |
|---|---|---|
| id | number | Numeric row ID. |
| card_number | string | Unique card number used for redemption and balance checks. |
| regular_gift_card_id | number | null | Set if this card was issued from a regular (template-based) gift card. |
| bulk_gift_card_id | number | null | Set if this card belongs to a bulk batch. |
| vendor_gift_card_id | number | null | Set if this card was issued by a third-party vendor. |
| amount_type | string | FIXED — card has a set value. Other types may exist for variable-amount cards. |
| currency | string | ISO 4217 currency code (e.g. SAR, AED). |
| amount | number | Original face value of the card. |
| remaining_balance | number | Current remaining balance. Equals amount for unpurchased or unused cards. |
| min_value / max_value | number | null | For variable-amount cards. null for FIXED cards. |
| is_active | boolean | true if the card is currently usable. |
| purchase_date | ISO datetime | null | When the card was purchased. null for unpurchased bulk cards. |
| expiry_date | ISO datetime | null | Card expiry datetime in UTC. |
| duration | number | null | Validity duration in days from purchase, if applicable. |
| user_id | number | null | Admin user who created the card, if applicable. |
| brand_id / branch_id | number | null | Scoping references. branch_id may be null for brand-wide cards. |
| form_details | object | null | Custom form data collected at purchase, if any. |
| created_at | ISO datetime | Record creation timestamp (UTC). Primary sort key. |
| updated_at | ISO datetime | null | Last update timestamp. null if never updated. |
Error Reference
| Status | Condition | Description |
|---|---|---|
| 404 | ?id= not found | No gift card exists with the specified numeric ID. |
| 404 | ?batch_id= not found | No bulk batch exists with the specified batch ID string. |
| 404 | ?balance=true card not found | No gift card matches the provided card_number. |
| 400 | Invalid bulk_gift_card_id | bulk_gift_card_id was provided but is not a valid number. |
Integration Notes
batch_id + download_csv=true is detected, the controller sets Content-Type: text/csv and streams the file. All other modes return application/json. Clients must branch on which response to expect based on the params they send.
data array with total: 0 — no error is thrown.
bulk_gift_card_id is the numeric row ID of the bulk batch record; used in Mode 6 to filter unpurchased cards. batch_id is the string reference (e.g. BATCH-001); used in Modes 4a and 4b to look up the batch itself.
Public — Country
Returns country configuration records including timezone, currency, and per-country redemption behaviour flags. Has two modes: single fetch by ID or a filtered list. Requires x-api-key authentication.
x-api-key request header. Returns 401 immediately if the header is absent or the value does not match the server key.
Mode is determined by the presence of ?id=. When supplied, returns a single country object. When absent, returns a paginated list with optional name/code filters. All list results are sorted by country_name ASC. Pagination uses offset-based skip, not a page parameter.
Fetches a single country record by its numeric row ID. Returns the country object directly under data (not an array). Returns 404 if no country exists with that ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | number | required | Numeric row ID of the country record (e.g. 2 for UAE). |
Returns a list of countries sorted by country_name ASC. Supports case-insensitive partial matching on name and code. Pagination is offset-based — use skip to advance pages, not a page parameter. The page field in the response is calculated server-side as Math.floor(skip / limit) + 1.
skip=10&limit=10. Passing page=2 has no effect — page is only an output field in the response.| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| limit | number | optional | 10 | Maximum number of records to return per call. |
| skip | number | optional | 0 | Number of records to skip (offset). Use to paginate: page 2 = skip=10, page 3 = skip=20, etc. |
| country_name | string | optional | — | Case-insensitive partial match (SQL ILIKE) on the country name. e.g. bah matches BAHRAIN. |
| country_id | string | optional | — | Case-insensitive partial match on the country code (e.g. UAE, KSA). Known codes: BHD, JOR, KSA, KWT, OMN, ONL, QAT, UAE, GBR. |
Country Object — Field Reference
| Field | Type | Description |
|---|---|---|
| id | number | Numeric row ID. Use this with ?id= for single fetch. |
| country_id | string | Short country code identifier. Known values: BHD, JOR, KSA, KWT, OMN, ONL, QAT, UAE, GBR. |
| country_name | string | Full country name in uppercase. Used as the primary sort key (ASC). |
| currency | string | ISO 4217 currency code for this country (e.g. AED, SAR, BHD). |
| is_active | boolean | Whether this country is currently enabled on the platform. |
| discount_wallet_redeem_otp | boolean | When true, discount wallet redemptions in this country require OTP verification. |
| discount_wallet_redeem_pin | boolean | When true, discount wallet redemptions require PIN verification instead of (or in addition to) OTP. |
| points_redeem_otp | boolean | When true, loyalty points redemptions require OTP verification. |
| points_redeem_pin | boolean | When true, loyalty points redemptions require PIN verification. |
| created_date | ISO datetime | UTC timestamp of when the country record was created. |
| updated_date | ISO datetime | UTC timestamp of the last update to this country record. |
| time_zone | object | null | Timezone configuration. null for some countries. When present, includes the sub-fields below. |
| time_zone.value | string | IANA timezone identifier, e.g. Asia/Dubai. |
| time_zone.label | string | Human-readable label with UTC offset, e.g. (GMT+4:00) Abu Dhabi, Muscat. |
| time_zone.offset | number | UTC offset in hours (integer). e.g. 4 for Gulf Standard Time. |
| time_zone.abbrev | string | Short timezone abbreviation, e.g. GST, AST. |
| time_zone.altName | string | Full timezone name, e.g. Gulf Standard Time. |
Error Reference
| Status | Condition | Description |
|---|---|---|
| 401 | Missing / invalid x-api-key | The x-api-key header is absent or does not match the server API key. Checked before any query logic runs. |
| 404 | ?id= not found | No country record exists with the provided numeric ID. |
Integration Notes
skip (offset), not page, to control pagination. The page field in the response is read-only and derived as Math.floor(skip / limit) + 1. To iterate pages, increment skip by limit on each request: skip=0, skip=10, skip=20, etc.
time_zone.value or any sub-field. When present, time_zone.value is a valid IANA identifier suitable for use with libraries like Intl.DateTimeFormat or dayjs/moment.
discount_wallet_redeem_otp, discount_wallet_redeem_pin, points_redeem_otp, points_redeem_pin) are per-country and control which verification step your frontend or POS should prompt for during redemption. Read these at startup and cache per country rather than hardcoding verification flows.
Public — Brand
Returns brand records including colour palette, CDN media URLs, social links, payment provider, and the full nested country object. Two modes: single fetch (by id, brand_Id, or brand_code) or a filtered paginated list. Requires x-api-key authentication.
x-api-key request header on every call. Returns 401 if absent or incorrect, before any query runs.
Mode is determined by the presence of id, brand_Id, or brand_code. Any one of those triggers single-fetch mode. Without them, the endpoint returns a paginated list sorted brand_name ASC. The hasFiles response field differs between modes — a detailed per-field object in single mode, true in list mode.
Fetches a single brand by numeric ID, brand code (brand_Id), or its alias brand_code. All three resolve the same record. Returns the full brand object plus a detailed hasFiles map showing which file fields have content. Returns 404 if no brand matches.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | number | one of | Numeric database primary key of the brand. |
| brand_Id | string | one of | Exact brand code, e.g. PKR02501. Case-insensitive in list mode; exact match in single mode. |
| brand_code | string | one of | Alias for brand_Id. Behaves identically. Use whichever your codebase prefers. |
Supply any one of id, brand_Id, or brand_code to enter single-fetch mode.
Returns a paginated list of brands sorted brand_name ASC. Supports name/code partial matching, country filtering (single or multi via comma-separated IDs), and a lightweight excludeFiles flag that replaces raw binary fields with booleans for lighter payloads. The response always includes "hasFiles": true at the root in list mode.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| page | number | optional | 1 | Page number for pagination. |
| limit | number | optional | 10 | Records per page. |
| brand_name | string | optional | — | Case-insensitive partial match (ILIKE) on the brand display name. |
| brand_Id | string | optional | — | Case-insensitive partial match on brand code. In list mode this is a partial search, unlike single mode where it is an exact match. |
| country_id | number | optional | — | Filter brands by a single country's numeric ID. |
| country_ids | string | optional | — | Comma-separated list of country IDs e.g. 1,2,3. Takes priority over country_id when both are supplied. |
| excludeFiles | string | optional | — | Pass "true" to replace raw binary file fields (logo_image, cover_image, cover_video, slider fields) with true (if file exists) or null (if not). Use this to reduce payload size when you only need to know whether a file is present. |
Brand Object — Field Reference
| Field | Type | Description |
|---|---|---|
| id | number | Numeric database primary key. |
| brand_name | string | Display name of the brand. Primary sort key (ASC). |
| brand_Id | string | Unique brand code identifier (e.g. PKR02501). Used in media URL paths. |
| description | string | Brand description text. May be an empty string. |
| social_links | string[] | Array of social media URLs. May be an empty array []. |
| logo_image | null | Raw binary field — always null in API responses. Use logo_image_url instead. |
| cover_image | null | Raw binary field — always null in API responses. Use cover_image_url instead. |
| cover_video | null | Raw binary field — always null in API responses. Use cover_video_url instead. |
| logo_image_url | string | null | CDN URL for the brand logo PNG. Pattern: /api/media/{brand_Id}/{brand_Id}_logo_image.png. |
| cover_image_url | string | null | CDN URL for the brand cover image. |
| cover_video_url | string | null | CDN URL for the brand cover video. null if no video is uploaded. |
| brand_main_color | hex string | Primary brand colour as a hex value (e.g. #ffffff). |
| brand_font_color | hex string | Text/font colour for branded UI surfaces. |
| brand_hover_color | hex string | Hover or interactive state colour. |
| brand_secondary_color | hex string | Secondary accent colour for branded surfaces. |
| payment_provider | string | Payment provider configured for this brand (e.g. OTHER, GEIDEA). |
| is_active | boolean | Whether the brand is currently active on the platform. |
| whatsapp_message | boolean | Whether WhatsApp messaging notifications are enabled for this brand. |
| email_message | boolean | Whether email notifications are enabled for this brand. |
| country_id | number | Foreign key referencing the brand's country record. |
| country | object | Full nested country object including redemption flags and time_zone. Same schema as the Public Country field reference. |
| created_date | ISO datetime | UTC timestamp of brand record creation. |
| updated_date | ISO datetime | UTC timestamp of the last update to this brand record. |
| hasFiles (single mode) | object | Detailed per-field boolean map. Each key corresponds to a file field and is true if content exists, false if not. Covers: logo_image, cover_image, cover_video, *_url variants, and slider_image_1/2/3 + URL variants. |
| hasFiles (list mode) | boolean | Always true at the response root in list mode. Per-item file presence is not individually mapped. |
Error Reference
| Status | Condition | Description |
|---|---|---|
| 401 | Missing / invalid x-api-key | The x-api-key header is absent or incorrect. Validated before any query logic runs. |
| 404 | Single fetch — brand not found | No brand matches the provided id, brand_Id, or brand_code. |
Integration Notes
logo_image, cover_image, and cover_video are raw binary DB columns and are always null in API responses. Use logo_image_url, cover_image_url, and cover_video_url for any display or download. The URL pattern is /api/media/{brand_Id}/{brand_Id}_{field_name}.png.
excludeFiles=true for lighter list payloads — when building index pages or dropdowns where you only need to know whether a file exists (not the content), pass excludeFiles=true. Binary fields are replaced with true or null, significantly reducing payload size for large result sets.
country_ids takes priority over country_id — when both are supplied in the same request, country_ids (comma-separated) wins and country_id is ignored. To filter by multiple countries, always use country_ids=1,2,3 rather than making multiple requests.
brand_Id behaves differently per mode — in single-fetch mode it is an exact match; in list mode it is a case-insensitive partial match (ILIKE). Use the single-fetch mode with the exact brand code when you need a guaranteed single result.
Public — Branch
Returns branch records with nested brand, country (with timezone), sections, and waiting list. Two modes: single fetch by ID (with capacity adjusted for live reservations) or a filtered paginated list. Requires x-api-key authentication.
x-api-key request header. Returns 401 before any query runs if absent or incorrect.
Mode is selected by the presence of ?id=. Without it, returns a paginated list. The public variant (/api/public/branch) always includes a waiting_list[] per branch — the private version does not. All list results sorted branch_name ASC.
Returns a single branch by numeric row ID. Section capacities are live-adjusted — each section's capacity reflects the raw capacity minus the count of current paid active reservations for that section. Also returns a per-field hasFiles object. Returns 404 if no branch matches.
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | number | required | Numeric database primary key of the branch (e.g. 1096). |
Returns a paginated list of branches sorted branch_name ASC. Each item includes nested brand, country, sections[], and waiting_list[]. Supports filtering by brand (single ID, comma-separated IDs, or brand code), country, name/code search, and feature flags. Setting limit >= 500 disables pagination and returns all results in one page.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| page | number | optional | 1 | Page number. |
| limit | number | optional | 10 | Records per page. Setting 500 or above disables pagination — returns all results in a single page with pages: 1. |
| branch_name | string | optional | — | Case-insensitive partial match (ILIKE) on branch display name. |
| branch_code | string | optional | — | Case-insensitive partial match on branch code. |
| brand_id | number | optional | — | Filter by a single brand's numeric ID. |
| brand_ids | string | optional | — | Comma-separated brand numeric IDs, e.g. 2,4,7. Takes priority over brand_id when both are present. |
| brand_Id | string | optional | — | Filter by brand code string (e.g. PKR02501). Takes priority over brand_ids — resolved to a numeric brand ID server-side before querying. |
| country | number | optional | — | Filter by country numeric ID. |
| isbookable | string | optional | — | Pass "true" to return only branches where is_active = true (bookable branches only). |
| play_enable | string | optional | — | Pass "true" or "false" to filter by the play_enable feature flag. |
| search | string | optional | — | Case-insensitive search across branch_name, branch_code, and numeric id. |
| excludeFiles | string | optional | — | Pass "true" to strip raw binary file columns (logo_image, cover_image, cover_video) for a lighter payload. |
Branch Object — Field Reference
| Field | Type | Description |
|---|---|---|
| id | number | Numeric database primary key. |
| branch_name | string | Display name. Primary sort key (ASC). |
| branch_code | string | Unique branch code identifier. Used in media URL paths. |
| brand_id | number | Foreign key referencing the parent brand. |
| country_id | number | Foreign key referencing the branch country. |
| latitude / longitude | number | null | GPS coordinates. May be null if not configured. |
| map_code | string | null | Google Maps share URL for the branch location. |
| address | string | null | Physical address text. |
| logo_image / cover_image / cover_video | null | Raw binary DB columns — always null in responses. Use the _url variants instead. |
| logo_image_url | string | null | CDN URL for branch logo. Pattern: /media/{brand_Id}/{branch_code}/logo_image.webp. |
| cover_image_url | string | null | CDN URL for branch cover image. |
| cover_video_url | string | null | CDN URL for branch cover video. null if not uploaded. |
| club_id | string | External loyalty club identifier. May be an empty string if not configured. |
| chefz_id | string | null | Chefz platform integration ID. |
| chefz_reservation | boolean | true if Chefz-sourced reservations are enabled for this branch. |
| is_active | boolean | Whether reservation booking is active. Filtered by isbookable=true. |
| is_active_waitinglist | boolean | Whether the waiting list feature is active for this branch. |
| is_active_payment | boolean | Whether payment collection at booking is enabled. |
| new_customer_reservation_otp | boolean | true if new customers must verify via OTP to complete a reservation. |
| new_customer_waiting_list_otp | boolean | true if new customers must verify via OTP to join the waiting list. |
| remaining_capacity_hide | boolean | true hides remaining slot capacity from the public-facing booking UI. |
| time_slot_hide | boolean | true hides time slots from the booking UI. |
| section_wise_time_slots | boolean | When true, time slots are managed and shown per section rather than for the whole branch. |
| show_slots_header | boolean | Display the slots header in the booking UI. |
| show_period_headers | boolean | Display period labels (e.g. Morning / Evening) in the booking UI. |
| show_time_range | boolean | Show start–end time ranges instead of single slot times. |
| child_seats | boolean | Whether child seat options are shown during booking. |
| play_enable | boolean | Play feature flag. Filterable via play_enable=true/false. |
| description | string | null | Branch description text. |
| waiting_list_config | object | null | Waiting list behaviour configuration. null if defaults apply. |
| venue_details | object | null | Custom availability UI text: availability_title, availability_subtitle, and font size overrides. null if not configured. |
| reservation_link | string | null | External reservation URL override, if applicable. |
| oracle_token_id | string | null | Oracle Simphony POS integration token. |
| orgShortName / locRef / rvcRef | string | null | Oracle POS reference fields for organisation, location, and revenue centre. |
| checkEmployeeRef / orderTypeRef | string | null | Additional Oracle POS integration references. |
| organization_id | number | Platform organisation FK. |
| created_date / updated_date | ISO datetime | UTC creation and last-update timestamps. |
| brand | object | Nested brand summary: id, brand_name, brand_Id, colour fields, payment_provider, is_active. |
| country | object | Nested country with currency, is_active, and time_zone (IANA value + label + offset). |
| sections | array | Branch sections — each with id, name, capacity, is_active. In single-fetch mode, capacity is adjusted by subtracting the current count of paid active reservations. |
| waiting_list | array | Current waiting list entries for the branch. Always included in public mode (/api/public/branch); absent in the private endpoint. May be an empty array. |
Error Reference
| Status | Condition | Description |
|---|---|---|
| 401 | Missing / invalid x-api-key | The x-api-key header is absent or does not match the server key. Evaluated before any query runs. |
| 404 | ?id= not found | No branch record exists with the specified numeric ID. |
Integration Notes
sections[].capacity is not the raw configured value. The server subtracts the count of current paid active reservations for that section before returning. Use this for real-time availability displays. The list mode returns raw capacity values.
waiting_list[] per branch is only included in responses from /api/public/branch. The private /api/branch endpoint does not include it. Always use the public endpoint if you need waiting list data alongside branch details.
limit=500 (or any value ≥ 500) to disable pagination entirely. The response returns all matching branches in a single page with pages: 1. Useful for populating dropdowns or branch maps at app startup.
brand_Id (string code) → brand_ids (comma-separated IDs) → brand_id (single numeric ID). When brand_Id is present it takes highest priority; it is resolved to a numeric ID server-side before the query runs.
logo_image, cover_image, and cover_video are raw binary DB columns and are always null in API responses. Use logo_image_url, cover_image_url, and cover_video_url for display. URL pattern: /media/{brand_Id}/{branch_code}/{field}.webp.
Salt Al Bahar — Public API
Unauthenticated public endpoints for Salt Al Bahar event slots, reservations, and wallet transactions. Used by the Salt Al Bahar booking flow and legacy public clients.
x-api-key or JWT. They are exposed under the /api/public/salt-al-bahar/ and /api/public/booking/ prefixes.
Returns available time slots for a Salt Al Bahar event on a given date, including capacity, pricing, entry fee, and bookable flags. Accounts for paid bookings and temporary cart holds.
| Parameter | Type | Required | Description |
|---|---|---|---|
| event_id | number | required | Salt Al Bahar event ID. |
| date | string | required | Booking date (YYYY-MM-DD). |
| party_size | number | optional | Party size for capacity checks. Default 1. |
Returns bookable slots grouped into regular_slots and mid_night_slots, with event rules and capacity counts. Only rules marked bookable are included.
| Field | Type | Required | Description |
|---|---|---|---|
| event_id | number | required | Event ID. |
| booking_date | string | required | Date (YYYY-MM-DD). |
| party_size | number | optional | Default 1. |
List, create, or update Salt Al Bahar event bookings (EventBooking). Creates a customer by mobile if one does not exist. PUT requires ?id={numeric_id}.
GET — query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| booking_id | string | optional | Filter by booking ID (e.g. SALT12345). |
| customer_id | number | optional | Filter by customer ID. |
| event_id | number | optional | Filter by event ID. |
| status | string | optional | Filter by booking status. |
| limit | number | optional | Page size. Default 10. |
| skip | number | optional | Offset pagination. Default 0. |
POST — body (create)
| Field | Type | Required | Description |
|---|---|---|---|
| mobile_number | string | required | Customer mobile (used as lookup / create key). |
| event_id | number | required | Event to book. |
| quantity | number | optional | Default 1. |
| event_rule_id | number | optional | Rule for pricing. |
| date | string | optional | Booking date. |
| start_time | string | optional | Slot start time. |
| end_time | string | optional | Slot end time. |
| payment_type | string | optional | CASH or CARD. Default CASH (marks PAID). |
PUT — body (update) · query ?id=
| Field | Type | Description |
|---|---|---|
| status | string | e.g. CANCELED |
| payment_status | string | Payment status update. |
| date | string | Reschedule booking date. |
| start_time | string | Updated start time. |
| end_time | string | Updated end time. |
Create wallet transactions or list transaction history. Summary available at /api/public/salt-al-bahar/transaction/summery (note: path spelling matches the API).
POST — body
| Field | Type | Required | Description |
|---|---|---|---|
| customer_id | number | required | Customer ID. |
| wallet_id | number | required | Wallet ID. |
| amount | number | required | Transaction amount. |
| transaction_type | string | required | CREDIT or DEBIT. |
| payment_method | string | optional | Payment method label. |
| note | string | optional | Transaction note. |
| event_booking_id | number | optional | Linked event booking. |
GET — query parameters
| Parameter | Type | Description |
|---|---|---|
| wallet_id | number | Filter by wallet. |
| customer_wallet_id | number | Filter by customer-wallet link. |
| limit | number | Page size. |
| skip | number | Offset. |
Returns aggregated wallet transaction summary. Supports the same filter query params as the list endpoint.
Public Booking API
Branch-level reservation slots and lists for the RestroEngage booking widget. Used by restroengage-dashboard and restroengage-reservation.
/api/public/booking. All endpoints below are GET in the current Nest API (list / fetch modes).
Returns section-based available slots for a branch on a given date, respecting custom availability rules, timezone, and live reservation counts.
| Parameter | Type | Required | Description |
|---|---|---|---|
| branchId | number | string | required | Branch numeric ID or branch_code. |
| date | string | required | Date (YYYY-MM-DD). |
| partySize | number | optional | Default 2. |
| customRuleId | number | optional | Force a specific custom availability rule. |
| showHidden | boolean | optional | Pass true to include hidden slots. |
Fetch one reservation by ?id= or a paginated list with optional filters (branch, customer mobile, date range, status).
| Parameter | Type | Description |
|---|---|---|
| id | number | Single reservation by row ID. |
| page | number | Page number. Default 1. |
| limit | number | Page size. Default 10. |
| branch_id | number | Filter by branch. |
| customer_mobile_number | string | Filter by customer mobile. |
Returns waiting list entries for a branch. Auto-expires READY entries older than 15 minutes to NOSHOW before responding. Use ?id= for a single entry or list filters for multiple.
Returns walk-in queue entries for a branch. Supports single fetch via ?id= or filtered list mode.