Introduction

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

Authenticating requests

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

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

To use our API, please contact our support team to request API access. Once approved, you can generate your access token through your admin panel by visiting Personal Access Tokens page.

Categories

Categories provide a hierarchical classification system for organising spaces within the platform.
The system uses a two-level structure where main categories (e.g., Food & Beverage, Retail) contain subcategories (e.g., Restaurant, Cafe, Hotel) that spaces can be assigned to.
This helps in filtering and discovering spaces based on their business type or industry.

List categories

GET
https://explore.pixalink.io.test
/api/categories
requires authentication

Returns a paginated list of categories. By default, only returns second level categories (categories that have a parent).

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

page
integer

Page number for pagination.

Example:
1
per_page
integer

Number of items per page.

Example:
15
include
string

Comma-separated list of relations to include. Allowed values:

  • parent
Example:
parent
sort
string

Field to sort by. Prefix with - for descending order. Allowed values:

  • name
  • created_at
  • updated_at
Example:
-created_at
filter[name]
string

Filter by name (partial match).

Example:
Restaurant
filter[parent_id]
integer

Filter by parent ID. If set to null or 0, returns main categories.

Example:
1
filter[id]
integer

Filter by ID.

Example:
1
filter[slug]
string

Filter by exact slug match.

Example:
restaurant

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/categories?page=1&per_page=15&include=parent&sort=-created_at&filter%5Bname%5D=Restaurant&filter%5Bparent_id%5D=1&filter%5Bid%5D=1&filter%5Bslug%5D=restaurant" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 5,
            "name": "Restaurant",
            "parent_id": 1
        },
        {
            "id": 6,
            "name": "Cafe",
            "parent_id": 1
        },
        {
            "id": 7,
            "name": "Hotel",
            "parent_id": 2
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/categories?page=1",
        "last": "{{$baseUrl}}/api/categories?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "{{$baseUrl}}/api/categories",
        "per_page": 15,
        "to": 3,
        "total": 3
    }
}
{
    "data": [
        {
            "id": 5,
            "name": "Restaurant",
            "parent_id": 1,
            "parent": {
                "id": 1,
                "name": "Food & Beverage"
            }
        },
        {
            "id": 6,
            "name": "Cafe",
            "parent_id": 1,
            "parent": {
                "id": 1,
                "name": "Food & Beverage"
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/categories?include=parent&page=1",
        "last": "{{$baseUrl}}/api/categories?include=parent&page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "{{$baseUrl}}/api/categories",
        "per_page": 15,
        "to": 2,
        "total": 2
    }
}

Credits

List Credits

GET
https://explore.pixalink.io.test
/api/credits
requires authentication

Get a paginated list of credits for the organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[customer_id]
integer

Filter by customer ID.

Example:
1
filter[type]
string

Filter by credit type.

Example:
Top Up
filter[space_id]
integer

Filter by space ID.

Example:
1
filter[amount]
string

Filter by amount with operators.

Example:
>100
sort
string

Sort field (created_at, amount).

Example:
-created_at
include
string

Include relationships (customer, space, reward).

Example:
customer
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/credits?filter%5Bcustomer_id%5D=1&filter%5Btype%5D=Top+Up&filter%5Bspace_id%5D=1&filter%5Bamount%5D=%3E100&sort=-created_at&include=customer&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "customer_id": 42,
            "space_id": 1,
            "amount": "50.00",
            "operation": "+",
            "type": "Top Up",
            "remarks": "Birthday top-up",
            "created_at": "2025-05-06T14:30:01.000000Z",
            "updated_at": "2025-05-06T14:30:01.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}
{
    "message": "Unauthenticated."
}
{
    "message": "This action is unauthorized."
}

Create Credit

POST
https://explore.pixalink.io.test
/api/credits
requires authentication

Creates a new credit entry for a customer (top up, deduct, revert, etc.).

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/credits" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 42,
    \"phone_number\": \"+60123456789\",
    \"amount\": \"50.00\",
    \"type\": \"Top Up\",
    \"space_id\": 1,
    \"remarks\": \"Birthday top-up\",
    \"custom_properties\": [],
    \"source_credit_id\": 10
}"
Example response:
{
    "data": {
        "id": 1,
        "customer_id": 42,
        "space_id": 1,
        "amount": "50.00",
        "operation": "+",
        "type": "Top Up",
        "remarks": "Birthday top-up",
        "created_at": "2025-05-06T14:30:01.000000Z",
        "updated_at": "2025-05-06T14:30:01.000000Z"
    }
}
{
    "message": "This action is unauthorized."
}
{
    "message": "The given data was invalid.",
    "errors": {
        "type": [
            "The selected type is invalid."
        ],
        "amount": [
            "The amount field is required."
        ]
    }
}

Get Credit Details

GET
https://explore.pixalink.io.test
/api/credits/{id}
requires authentication

Retrieve detailed information about a specific credit.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the credit.

Example:
3
credit
integer
required

The ID of the credit.

Example:
1

Query Parameters

include
string

Relationships to include (customer, space, reward).

Example:
customer

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/credits/3?include=customer" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "customer_id": 42,
        "space_id": 1,
        "amount": "50.00",
        "operation": "+",
        "type": "Top Up",
        "remarks": "Birthday top-up",
        "created_at": "2025-05-06T14:30:01.000000Z",
        "updated_at": "2025-05-06T14:30:01.000000Z"
    }
}
{
    "message": "This action is unauthorized."
}
{
    "message": "Record not found."
}

Customer Paid Memberships

List Customer Paid Memberships

GET
https://explore.pixalink.io.test
/api/customer_paid_memberships
requires authentication

Returns a paginated list of customer paid membership instances. Records are scoped to the authenticated user's organisation via the model's global scope.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated relationships to include. Available: customer, paidMembershipType, transactions, payments, activePayment. Use payments to retrieve all payment records for reconciliation, or activePayment to retrieve only the currently linked payment.

Example:
paidMembershipType,customer
filter[customer_id]
integer

Filter by customer ID.

Example:
1
filter[paid_membership_type_id]
integer

Filter by membership type ID.

Example:
1
filter[is_active]
boolean

Filter by active flag.

Example:
true
filter[billing_cycle]
string

Filter by billing cycle (monthly or yearly).

Example:
yearly
filter[expires_at]
string

Filter by expiry date using comparison operators (>, <, =). ISO 8601 date.

Example:
>2025-04-01
sort
string

Sort field and direction. Prefix with - for descending. Available: created_at, starts_at, expires_at. Defaults to -created_at.

Example:
-expires_at
per_page
integer

Number of records per page. Defaults to 15.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customer_paid_memberships?include=paidMembershipType%2Ccustomer&filter%5Bcustomer_id%5D=1&filter%5Bpaid_membership_type_id%5D=1&filter%5Bis_active%5D=1&filter%5Bbilling_cycle%5D=yearly&filter%5Bexpires_at%5D=%3E2025-04-01&sort=-expires_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
Headers
cache-control: no-cache, private
content-type: application/json
content-security-policy: default-src 'self'; script-src https: 'self' 'unsafe-inline' 'unsafe-eval' blob: http://localhost:5173; style-src https: 'self' 'unsafe-inline' http://localhost:5173; font-src https: 'self' data:; img-src https: 'self' data: blob:; media-src https: 'self' blob:; connect-src https: wss: 'self' ws://localhost:5173; frame-src https: 'self' phpstorm:; worker-src 'self' blob:; frame-ancestors 'self'; base-uri 'self'; upgrade-insecure-requests; form-action 'self'
referrer-policy: strict-origin-when-cross-origin
permissions-policy: geolocation=(), microphone=(), camera=(self), payment=(self), usb=(), magnetometer=(), gyroscope=(), accelerometer=(), autoplay=(), encrypted-media=(), fullscreen=*, picture-in-picture=()
x-content-type-options: nosniff
x-frame-options: DENY
access-control-allow-origin: *
{
    "message": "Unauthenticated."
}

Assign a Paid Membership

POST
https://explore.pixalink.io.test
/api/customer_paid_memberships
requires authentication

Assigns a paid membership of the given type and billing cycle to a customer. Any existing active membership for that customer is automatically deactivated. Delegates lifecycle logic to PaidMembershipService::assignMembership, which records a ManualAssign transaction and issues any rewards configured on the membership type.

If the integrator has already collected payment in their own system, an optional payment object may be supplied. When present, a Payment row is recorded against the membership and a ManualPayment transaction is logged. The accepted payment.method values (cash, card, e_wallet) are deliberately limited to manually-recorded instruments — gateway methods are not accepted via this endpoint. Omit payment entirely for free/comp assignments.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/customer_paid_memberships" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 1,
    \"paid_membership_type_id\": 1,
    \"billing_cycle\": \"monthly\",
    \"starts_at\": \"2025-04-01\",
    \"remarks\": \"Manually assigned by support after refund.\",
    \"payment\": {
        \"method\": \"cash\",
        \"amount\": 99,
        \"currency\": \"MYR\",
        \"reference_id\": \"POS-12345\",
        \"remarks\": \"Paid at counter\"
    }
}"
Example response:
{
    "data": {
        "id": 1,
        "membership_status": "active",
        "membership_type_name": "VIP Gold",
        "billing_cycle": "monthly",
        "starts_at": "2025-04-01",
        "expires_at": "2025-05-01",
        "is_active": true
    },
    "message": "Paid membership assigned successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "billing_cycle": [
            "The selected billing cycle is not available for this membership type."
        ]
    }
}

Show Customer Paid Membership

GET
https://explore.pixalink.io.test
/api/customer_paid_memberships/{id}
requires authentication

Retrieves a single customer paid membership by ID. Cross-organisation access returns 404.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer paid membership.

Example:
1
customer_paid_membership
integer
required

The ID of the membership instance.

Example:
1

Query Parameters

include
string

Comma-separated relationships to include. Available: customer, paidMembershipType, transactions, payments, activePayment. Use payments to retrieve all payment records for reconciliation, or activePayment to retrieve only the currently linked payment.

Example:
payments

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customer_paid_memberships/1?include=payments" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "membership_status": "active",
        "membership_type_name": "VIP Gold",
        "billing_cycle": "monthly",
        "starts_at": "2025-04-01",
        "expires_at": "2025-05-01",
        "auto_renew": false,
        "is_active": true
    }
}
{
    "message": "Record not found"
}

Update Customer Paid Membership

PUT
PATCH
https://explore.pixalink.io.test
/api/customer_paid_memberships/{id}
requires authentication

Either extends the membership (via extend_days + remarks) or toggles auto_renew. The two operations are mutually exclusive — sending both at once returns a 422.

Extending delegates to PaidMembershipService::extendMembership, which records a ManualExtend transaction and sends the customer the configured notification.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer paid membership.

Example:
1
customer_paid_membership
integer
required

The ID of the membership to update.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/customer_paid_memberships/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"extend_days\": 14,
    \"remarks\": \"Goodwill extension after service outage.\",
    \"auto_renew\": true
}"
Example response:
{
    "data": {
        "id": 1,
        "membership_status": "active",
        "membership_type_name": "VIP Gold",
        "billing_cycle": "monthly",
        "starts_at": "2025-04-01",
        "expires_at": "2025-05-15",
        "auto_renew": true,
        "is_active": true
    },
    "message": "Paid membership updated successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "extend_days": [
            "The extend days field prohibits auto_renew from being present."
        ]
    }
}

Cancel Customer Paid Membership

DELETE
https://explore.pixalink.io.test
/api/customer_paid_memberships/{id}
requires authentication

Cancels (deactivates) the customer's paid membership. Sets is_active to false and records a Cancelled transaction for the audit trail. The row is not hard-deleted — historical lookups remain intact.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer paid membership.

Example:
1
customer_paid_membership
integer
required

The ID of the membership to cancel.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/customer_paid_memberships/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
[Empty response]

Customer Rewards

APIs for managing customer rewards

List Customer Rewards

GET
https://explore.pixalink.io.test
/api/customer_rewards
requires authentication

Returns a paginated list of customer rewards belonging to the authenticated user's organisation. Results can be filtered, sorted and include related data through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include:

  • customer
  • reward
  • validatedAtSpace
  • validatedByUser
Example:
customer,reward,validatedAtSpace,validatedByUser
filter[status]
string

Filter by reward status (Pending, Used, Expired).

Example:
Pending
filter[code]
string

Filter by exact reward code match.

Example:
ABC123
filter[expired_at]
string

Filter by expiry date with operators (>, <, =).

Example:
>2024-01-01
filter[used_at]
string

Filter by redemption date with operators (>, <, =).

Example:
<2024-12-31
filter[customer_id]
integer

Filter by customer ID.

Example:
1
filter[reward_id]
integer

Filter by reward ID.

Example:
1
filter[validated_at_space_id]
integer

Filter by validation space ID.

Example:
1
filter[validated_by_user_id]
integer

Filter by validator user ID.

Example:
1
sort
string

Sort field and direction. Allowed fields: expired_at, used_at, created_at.

Example:
-created_at
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customer_rewards?include=customer%2Creward%2CvalidatedAtSpace%2CvalidatedByUser&filter%5Bstatus%5D=Pending&filter%5Bcode%5D=ABC123&filter%5Bexpired_at%5D=%3E2024-01-01&filter%5Bused_at%5D=%3C2024-12-31&filter%5Bcustomer_id%5D=1&filter%5Breward_id%5D=1&filter%5Bvalidated_at_space_id%5D=1&filter%5Bvalidated_by_user_id%5D=1&sort=-created_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
   "data":[
     {
        "id": 1,
        "customer_id": 1,
        "reward_id": 1,
        "status": "Pending",
        "code": "REWARD123",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": null,
        "created_at": "2024-02-11T00:00:00.000000Z",
        "updated_at": "2024-02-11T00:00:00.000000Z",
        "customer" : {
           "id": 1,
           "name": "John Smith",
           "email": "john.smith@example.com",
           "phone_number": "+60123456789",
           "gender": 1,
           "date_of_birth": "1990-05-15",
           "source": "WhatsApp",
           "status": "Converted",
           "current_point": 2500,
           "created_at": "2024-01-15T08:30:00.000000Z",
           "updated_at": "2024-02-01T14:22:33.000000Z",
           "notes": "Prefers to be contacted via WhatsApp",
           "is_manually_assign_tier": 0,
           "current_credits": 150,
           "birthday_month": 5,
           "tags": ["VIP", "Regular Customer"],
           "space_id": 1,
           "tier_id": 1,
           "organisation_id": 1,
         }
       },
     ],
    "links": {
      "first": "{{$baseUrl}}/customer_rewards?page=1",
      "last": "{{$baseUrl}}/customer_rewards?page=5",
      "prev": null,
      "next": "{{$baseUrl}}/customer_rewards?page=2"
    },
    "meta": {
      "current_page": 1,
      "from": 1,
      "last_page": 5,
      "links": [
        {
          "url": null,
          "label": "&laquo; Previous",
          "active": false
        },
        {
          "url": "{{$baseUrl}}/customer_rewards?page=1",
          "label": "1",
          "active": true
        },
        {
          "url": "{{$baseUrl}}/customer_rewards?page=2",
          "label": "2",
          "active": false
        },
        {
          "url": "{{$baseUrl}}/customer_rewards?page=3",
          "label": "3",
          "active": false
        },
        {
          "url": "{{$baseUrl}}/customer_rewards?page=2",
          "label": "Next &raquo;",
          "active": false
        }
      ],
      "path": "{{$baseUrl}}/customer_rewards",
      "per_page": 15,
      "to": 15,
      "total": 68
    }
  }

Create Customer Reward

POST
https://explore.pixalink.io.test
/api/customer_rewards
requires authentication

Assigns a reward to a customer and processes the point redemption. This endpoint performs several validation checks:

  1. Verifies that the customer has sufficient points for the reward
  2. Checks if the reward has reached its total availability limit (if configured)
  3. For one-time rewards, ensures the customer hasn't already redeemed it
  4. Validates that both customer and reward belong to the authenticated organisation

Upon successful validation, the system will:

  • Deduct points from the customer's balance
  • Create a customer reward record
  • Generate a unique redemption code
  • If mark_as_redeemed is true, immediately mark the reward as used

Note: The reward's points cost is determined by its configured amount. Ensure the customer has sufficient points before making this request to avoid validation errors.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/customer_rewards" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 1,
    \"reward_id\": 1,
    \"mark_as_redeemed\": false,
    \"currency_type\": \"point\",
    \"validated_at_space_id\": 1,
    \"validated_by_user_id\": 1
}"
Example response:
{
    "data": {
        "id": 1,
        "customer_id": 1,
        "reward_id": 1,
        "status": "Pending",
        "code": "REWARD123",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": null,
        "created_at": "2024-02-11T00:00:00.000000Z",
        "updated_at": "2024-02-11T00:00:00.000000Z"
    },
    "message": "Customer reward created successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "reward_id": [
            "This reward cannot be redeemed as it has reached its maximum redemption limit."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "reward_id": [
            "This reward has already been used/redeemed. (Single redemption reward cannot be redeemed twice)"
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "reward_id": [
            "Customer does not have enough point to redeem"
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "customer_id": [
            "The selected customer id is invalid."
        ],
        "reward_id": [
            "The selected reward id is invalid."
        ]
    }
}

Get Customer Reward Details

GET
https://explore.pixalink.io.test
/api/customer_rewards/{id}
requires authentication

Retrieves detailed information about a specific customer reward.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer reward.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include (customer, reward, validatedAtSpace, validatedByUser).

Example:
customer,reward,validatedAtSpace,validatedByUser

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customer_rewards/1?include=customer%2Creward%2CvalidatedAtSpace%2CvalidatedByUser" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "customer_id": 1,
        "reward_id": 1,
        "status": "Pending",
        "code": "REWARD123",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": null,
        "created_at": "2024-02-11T00:00:00.000000Z",
        "updated_at": "2024-02-11T00:00:00.000000Z"
    }
}

Update Customer Reward

PUT
PATCH
https://explore.pixalink.io.test
/api/customer_rewards/{id}
requires authentication

Updates a customer reward's details.
Can update status, expiry date, and usage date.
Cannot modify rewards that are Expired or Used for more than 1 hour.
Used rewards can be updated within 1 hour of being marked as used.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer reward.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/customer_rewards/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"Used\",
    \"expired_at\": \"2024-12-31T23:59:59Z\",
    \"used_at\": \"2024-02-10T15:30:00Z\",
    \"validated_at_space_id\": 1,
    \"validated_by_user_id\": 1
}"
Example response:
{
    "data": {
        "id": 1,
        "status": "Used",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": "2024-02-11T00:00:00.000000Z",
        "updated_at": "2024-02-11T00:00:00.000000Z"
    },
    "message": "Customer reward updated successfully"
}
{
    "data": {
        "id": 1,
        "status": "Pending",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": null,
        "updated_at": "2024-02-11T00:00:00.000000Z"
    },
    "message": "Customer reward updated successfully"
}
{
    "message": "The selected status is invalid.",
    "errors": {
        "status": [
            "The selected status is invalid."
        ]
    }
}
{
    "message": "Cannot update expired rewards or rewards used more than 1 hour ago",
    "errors": {
        "status": [
            "Cannot update expired rewards or rewards used more than 1 hour ago."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "used_at": [
            "used_at can only be set when status is Used."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "used_at": [
            "The used at must be a date before or equal to now."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "expired_at": [
            "The expired at must be a date after now."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "expired_at": [
            "The expired at is not a valid date."
        ],
        "used_at": [
            "The used at is not a valid date."
        ]
    }
}

Delete Customer Reward

DELETE
https://explore.pixalink.io.test
/api/customer_rewards/{id}
requires authentication

Revokes/deletes a pending customer reward. Cannot revoke Used or Expired rewards.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer reward.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/customer_rewards/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "message": "Customer reward revoked successfully"
}
{
    "message": "Cannot revoke used or expired rewards"
}

Customers

List Customers

GET
https://explore.pixalink.io.test
/api/customers
requires authentication

Returns a paginated list of customers belonging to the authenticated user's organisation.
Results can be filtered, sorted and include related data through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include:

  • tier
  • space
  • tags
  • address
  • activePaidMembership.paidMembershipType (includes active paid membership with type details)
Example:
tier,activePaidMembership.paidMembershipType
filter[phone_number]
string

Filter by phone number (partial match). Searches for phone numbers containing the provided value.

Example:
88888888 (matches +60188888888)
filter[email]
string

Filter by email match.

Example:
customer@example.com
filter[gender]
integer

Filter by gender. Must be one of:

  • 0 (Female)
  • 1 (Male)
Example:
1
filter[source]
string

Filter by customer source. Must be one of:

  • Email
  • Phone
  • Direct
  • Reservation
  • WhatsApp
  • StoreHub
  • Loyverse
  • Softinn
  • Loyalty
Example:
WhatsApp
filter[status]
string

Filter by customer status. Must be one of:

  • Lead
  • Open
  • Replied
  • Opportunity
  • Quotation
  • Lost Quotation
  • Interested
  • Converted
  • Do Not Contact
  • Blocked
Example:
Lead
filter[current_point]
string

Filter by points with operators (>, <, =).

Example:
>100
filter[current_credits]
string

Filter by credits with operators (>, <, =).

Example:
>50
filter[created_at]
string

Filter by creation date with operators (>, <, =). You can:

  • Find customers created on a specific date: 2024-01-01
  • Find customers created after a date: >2024-01-01
  • Find customers created before a date: <2024-01-01
  • Find customers created between dates: >2024-01-01,<2024-01-31 Use ISO 8601 format (YYYY-MM-DD).
Example:
2024-01-01
filter[updated_at]
string

Filter by last update date with operators (>, <, =). Use ISO 8601 format (YYYY-MM-DD).

Example:
<2024-12-31
filter[tier]
string

Filter by tier ID.

Example:
1
filter[space]
string

Filter by space ID.

Example:
1
filter[has_tags]
string

Filter by tag name.

Example:
VIP
filter[name]
string

Filter by customer name (partial match).

Example:
John
filter[birthday_month]
integer

Filter by birth month (1-12).

Example:
10
sort
string

Sort field and direction. Allowed fields: name, created_at, current_point, current_credits.

Example:
-created_at
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customers?include=tier%2CactivePaidMembership.paidMembershipType&filter%5Bphone_number%5D=88888888+%28matches+%2B60188888888%29&filter%5Bemail%5D=customer%40example.com&filter%5Bgender%5D=1&filter%5Bsource%5D=WhatsApp&filter%5Bstatus%5D=Lead&filter%5Bcurrent_point%5D=%3E100&filter%5Bcurrent_credits%5D=%3E50&filter%5Bcreated_at%5D=2024-01-01&filter%5Bupdated_at%5D=%3C2024-12-31&filter%5Btier%5D=1&filter%5Bspace%5D=1&filter%5Bhas_tags%5D=VIP&filter%5Bname%5D=John&filter%5Bbirthday_month%5D=10&sort=-created_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "John Smith",
            "email": "john.smith@example.com",
            "phone_number": "+60123456789",
            "gender": 1,
            "date_of_birth": "1990-05-15",
            "source": "WhatsApp",
            "status": "Converted",
            "current_point": 2500,
            "created_at": "2024-01-15T08:30:00.000000Z",
            "updated_at": "2024-02-01T14:22:33.000000Z",
            "notes": "Prefers to be contacted via WhatsApp",
            "is_manually_assign_tier": 0,
            "current_credits": 150,
            "birthday_month": 5,
            "tags": [
                "VIP",
                "Regular Customer"
            ],
            "space_id": 1,
            "tier_id": 1,
            "organisation_id": 1,
            "tier": {
                "id": 1,
                "name": "Gold Member",
                "sort": 2,
                "min_point": 2000,
                "color": "#FFD700",
                "is_manual_assign": 1,
                "point_multiplier": 1.5,
                "perks": {
                    "birthday_multiplier": 2
                },
                "tier_configuration_id": 1
            },
            "space": {
                "id": 1,
                "uuid": "f2d75bf6-3cb8-305c-8f70-f71fe697cba3",
                "name": "Main Branch",
                "slug": "main-branch",
                "matterport_model_id": null,
                "description": "Our flagship store in the city centre",
                "visibility": "public",
                "email": "main@example.com",
                "phone_number": "+60312345678",
                "website": "{{$baseUrl}}",
                "social_media": {
                    "facebook": "example",
                    "instagram": "example"
                },
                "organisation_id": 1,
                "category_id": 1,
                "visits": 1250,
                "created_at": "2023-01-01T00:00:00.000000Z",
                "updated_at": "2024-01-15T08:30:00.000000Z",
                "deleted_at": null,
                "links": {
                    "public_url": "{{$baseUrl}}/spaces/main-branch"
                }
            },
            "address": {
                "address_line_1": "123 Customer Street",
                "address_line_2": "Unit 4B",
                "city": "Kuala Lumpur",
                "state": "Federal Territory of Kuala Lumpur",
                "country": "Malaysia",
                "postal_code": "50000",
                "full_address": "123 Customer Street, Unit 4B, Kuala Lumpur, Federal Territory of Kuala Lumpur, 50000, Malaysia"
            },
            "paidMembership": {
                "id": 123,
                "membership_status": "active",
                "membership_type_name": "VIP Gold",
                "billing_cycle": "monthly",
                "starts_at": "2024-01-01",
                "expires_at": "2024-02-01",
                "is_active": true
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/customers?page=1",
        "last": "{{$baseUrl}}/customers?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/customers?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/customers?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "{{$baseUrl}}/customers?page=2",
                "label": "2",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/customers?page=3",
                "label": "3",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/customers?page=2",
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "{{$baseUrl}}/customers",
        "per_page": 15,
        "to": 15,
        "total": 68
    }
}

Create Customer

POST
https://explore.pixalink.io.test
/api/customers
requires authentication

Creates a new customer in the system.
The customer will be associated with the authenticated user's organisation.
Supports tag assignment.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/customers" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"John Smith\",
    \"email\": \"john.smith@example.com\",
    \"phone_number\": \"+60123456789\",
    \"gender\": 1,
    \"date_of_birth\": \"1990-01-01\",
    \"space_id\": 1,
    \"source\": \"WhatsApp\",
    \"status\": \"Lead\",
    \"tier_id\": 1,
    \"is_manually_assign_tier\": true,
    \"tags\": [
        \"aliquid\"
    ],
    \"notes\": \"Prefers to be contacted via WhatsApp\",
    \"address\": {
        \"address_line_1\": \"123 Main Street\",
        \"address_line_2\": \"Unit 4B\",
        \"country\": \"Malaysia\",
        \"state\": \"Selangor\",
        \"city\": \"Petaling Jaya\",
        \"postal_code\": \"46150\"
    }
}"
Example response:
{
   "data": {
       "id": 1,
       "name": "John Doe",
       "email": "john@example.com",
       "phone_number": "+60123456789",
       "gender": 1,
       "date_of_birth": "1990-01-01",
       "source": "WhatsApp",
       "status": "Lead",
       "current_point": 0,
       "notes": "Prefers evening appointments",
       "custom_properties": null,
       "is_manually_assign_tier": 0,
       "current_credits": 0,
       "birthday_month": 1,
       "space_id": 1,
       "organisation_id": 1,
       "created_at": "2025-02-01T00:00:00.000000Z",
       "updated_at": "2025-02-01T00:00:00.000000Z",
       "address": {
            "address_line_1": "No 39, Jalan Desa 1/1",
            "address_line_2": "Taman Desa",
            "city": "Petaling Jaya",
            "state": "Selangor",
            "country": "Malaysia",
            "postal_code": "58100",
            "full_address": "No 39, Jalan Desa 1/1, Taman Desa, Petaling Jaya, Selangor, 58100, Malaysia",
        }
   },
   "message": "Customer created successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "The email address is already taken."
        ],
        "phone_number": [
            "The phone number is already taken."
        ],
        "source": [
            "The selected source is invalid."
        ],
        "status": [
            "The selected status is invalid."
        ]
    }
}

Show Customer Details

GET
https://explore.pixalink.io.test
/api/customers/{id}
requires authentication

Retrieves detailed information about a specific customer, including any requested relationships.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer to delete.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • tier
  • space
  • address
  • tags
  • activePaidMembership.paidMembershipType (includes active paid membership with type details)
Example:
tier,activePaidMembership.paidMembershipType

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/customers/1?include=tier%2CactivePaidMembership.paidMembershipType" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com",
        "phone_number": "+60123456789",
        "gender": 1,
        "date_of_birth": "1990-01-01",
        "source": "WhatsApp",
        "status": "Lead",
        "current_point": 0,
        "notes": "Prefers evening appointments",
        "custom_properties": null,
        "is_manually_assign_tier": 0,
        "current_credits": 0,
        "birthday_month": 1,
        "space_id": 1,
        "organisation_id": 1,
        "created_at": "2025-02-01T00:00:00.000000Z",
        "updated_at": "2025-02-01T00:00:00.000000Z",
        "tier_id": 1,
        "tier": {
            "id": 1,
            "name": "Bronze",
            "points_required": 0
        },
        "paidMembership": {
            "id": 123,
            "membership_status": "active",
            "membership_type_name": "VIP Gold",
            "billing_cycle": "monthly",
            "starts_at": "2024-01-01",
            "expires_at": "2024-02-01",
            "is_active": true
        }
    }
}
{
    "message": "Record not found"
}

Update Customer

PUT
PATCH
https://explore.pixalink.io.test
/api/customers/{id}
requires authentication

Updates an existing customer's information.
All fields are optional.
Existing tags will be synced with the provided tags array if included.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer to delete.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/customers/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"John Doe\",
    \"email\": \"john@example.com\",
    \"phone_number\": \"+60123456789\",
    \"gender\": \"1\",
    \"date_of_birth\": \"1990-01-01\",
    \"space_id\": 1,
    \"source\": \"WhatsApp\",
    \"status\": \"Lead\",
    \"tier_id\": 1,
    \"is_manually_assign_tier\": true,
    \"tags\": [
        \"VIP\",
        \"Frequent Visitor\"
    ],
    \"notes\": \"Prefers evening appointments\",
    \"address\": {
        \"address_line_1\": \"No 39, Jalan Desa 1\\/1\",
        \"address_line_2\": \"Taman Desa\",
        \"country\": \"Malaysia\",
        \"state\": \"Selangor\",
        \"city\": \"Petaling Jaya\",
        \"postal_code\": \"58100\"
    }
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com",
        "phone_number": "+60123456789",
        "gender": 1,
        "date_of_birth": "1990-01-01",
        "source": "WhatsApp",
        "status": "Lead",
        "current_point": 0,
        "notes": "Prefers evening appointments",
        "custom_properties": null,
        "is_manually_assign_tier": 0,
        "current_credits": 0,
        "birthday_month": 1,
        "space_id": 1,
        "organisation_id": 1,
        "created_at": "2025-02-01T00:00:00.000000Z",
        "updated_at": "2025-02-01T00:00:00.000000Z",
        "address": {
             "address_line_1": "No 39, Jalan Desa 1/1",
             "address_line_2": "Taman Desa",
             "city": "Petaling Jaya",
             "state": "Selangor",
             "country": "Malaysia",
             "postal_code": "58100",
             "full_address": "No 39, Jalan Desa 1/1, Taman Desa, Petaling Jaya, Selangor, 58100, Malaysia",
        }
    },
    "message": "Customer updated successfully"
}
{
    "message": "Customer not found"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "The email address is already taken."
        ],
        "phone_number": [
            "The phone number is already taken."
        ],
        "source": [
            "The selected source is invalid."
        ],
        "status": [
            "The selected status is invalid."
        ]
    }
}

Delete Customer

DELETE
https://explore.pixalink.io.test
/api/customers/{id}
requires authentication

Queues a customer for deletion.
The deletion process runs asynchronously.
All related data will be deleted including rewards, transactions, and media (if any).

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the customer to delete.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/customers/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "message": "Customer deletion has been queued and will be processed shortly"
}
{
    "message": "Record not found"
}

Bulk Import Customers

POST
https://explore.pixalink.io.test
/api/customers/bulk-import
requires authentication

Import multiple customers asynchronously.
The operation is queued and processed in chunks of 100 records.
Limited to 1,000 customers per request and rate limited to 10 requests per minute.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/customers/bulk-import" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customers\": [
        {
            \"name\": \"John Doe\",
            \"email\": \"john@example.com\",
            \"phone_number\": \"+60123456789\",
            \"gender\": 1,
            \"date_of_birth\": \"1990-01-01\",
            \"source\": \"WhatsApp\",
            \"status\": \"Lead\",
            \"notes\": \"VIP customer\",
            \"tags\": [
                \"VIP\",
                \"WhatsApp\"
            ]
        }
    ],
    \"space_id\": 1
}"
Example response:
{
    "message": "Bulk customer import has been queued and will be processed shortly"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "customers": [
            "The customers must not have more than 1000 items."
        ],
        "customers.*.email": [
            "The customers.0.email has already been taken."
        ],
        "customers.*.phone_number": [
            "The customers.0.phone_number must be a valid phone number."
        ]
    }
}
{
    "message": "Too Many Attempts."
}

Organisations

List Organisations

GET
https://explore.pixalink.io.test
/api/organisations
requires authentication

Returns a paginated list of organisations. Vendors see only their own organisation. Super admins with "View Any Organisation" permission see all organisations.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter by organisation name (partial match).

Example:
Acme
sort
string

Sort field. Allowed: id, name, created_at.

Example:
-id
per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/organisations?filter%5Bname%5D=Acme&sort=-id&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Acme Corp",
            "friendly_name": "Acme",
            "email": "hello@acme.com",
            "phone_number": "+60123456789",
            "pos_provider": null,
            "ecommerce_provider": null,
            "features": {
                "loyalty": true,
                "credits": false,
                "tiering": false,
                "ecommerce_integration": false
            },
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Show Organisation

GET
https://explore.pixalink.io.test
/api/organisations/{id}
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The organisation ID.

Example:
1

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/organisations/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Acme Corp",
        "features": {
            "loyalty": true,
            "credits": false,
            "tiering": false,
            "ecommerce_integration": false
        }
    }
}
{
    "message": "This action is unauthorized."
}

Update Organisation

PUT
PATCH
https://explore.pixalink.io.test
/api/organisations/{id}
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The organisation ID.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/organisations/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Acme Corp\",
    \"friendly_name\": \"Acme\",
    \"email\": \"hello@acme.com\",
    \"phone_number\": \"+60123456789\"
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "Updated Name"
    },
    "message": "Organisation updated successfully"
}
{
    "message": "...",
    "errors": {}
}

Subscriptions

Stripe subscriptions belonging to an organisation.


List Organisation Subscriptions

GET
https://explore.pixalink.io.test
/api/organisations/{organisation_id}/subscriptions
requires authentication

Returns a paginated list of Stripe subscriptions for the specified organisation. Only the organisation's own members can access this endpoint.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

organisation_id
integer
required

The organisation ID.

Example:
1

Query Parameters

per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/organisations/1/subscriptions?per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "type": "default",
            "stripe_id": "sub_1ABC",
            "stripe_status": "active",
            "stripe_price": "price_1ABC",
            "quantity": 1,
            "trial_ends_at": null,
            "ends_at": null,
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "total": 1
    }
}
{
    "data": [
        {
            "id": 1,
            "type": "default",
            "stripe_id": "sub_1ABC",
            "stripe_status": "active",
            "stripe_price": "price_1ABC",
            "quantity": 1,
            "trial_ends_at": null,
            "ends_at": null,
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}
{
    "message": "This action is unauthorized."
}

POS Credits

List POS credits

GET
https://explore.pixalink.io.test
/api/posCredit
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[status]
string

Filter by status (pending, adopted).

Example:
adopted
filter[space_id]
integer

Filter by space ID.

Example:
1
filter[ref_id]
string

Filter by ref_id.

Example:
REF-123
filter[transaction_timestamp]
string

Filter by date (YYYY-MM-DD).

Example:
2025-05-06
filter[amount]
string

Filter by amount with operators.

Example:
>50
sort
string

Sort field. Allowed: transaction_timestamp, amount, created_at.

Example:
-created_at
include
string

Relationships to include (space).

Example:
space
per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/posCredit?filter%5Bstatus%5D=adopted&filter%5Bspace_id%5D=1&filter%5Bref_id%5D=REF-123&filter%5Btransaction_timestamp%5D=2025-05-06&filter%5Bamount%5D=%3E50&sort=-created_at&include=space&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "ref_id": "CREDIT-12345",
            "transaction_timestamp": "2025-05-06T14:30:00.000000Z",
            "amount": "50.00",
            "status": "adopted",
            "pos_provider": "eats365",
            "organisation_id": 1,
            "space_id": 1,
            "credit_id": 101,
            "void_credit_id": null,
            "payload": {
                "terminal": "T001"
            },
            "created_at": "2025-05-06T14:30:01.000000Z",
            "updated_at": "2025-05-06T14:30:01.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}
{
    "message": "This action is unauthorized."
}

Create POS Credit

POST
https://explore.pixalink.io.test
/api/posCredit
requires authentication

Ingests a POS credit record. If a customer is identified (via customer_id or phone_number), a credit wallet entry is created and the POS credit status is set to adopted. Without customer identification the record is stored as pending for later adoption.

  • Positive amounts create a Top Up credit.
  • Negative amounts create a Refund credit.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/posCredit" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"ref_id\": \"REF-20250506-001\",
    \"transaction_timestamp\": \"2025-05-06T14:30:00Z\",
    \"amount\": 5000,
    \"payload\": {
        \"receipt_no\": \"RCP-001\",
        \"terminal_id\": \"T01\"
    },
    \"space_id\": 1,
    \"customer_id\": 42,
    \"phone_number\": \"+60123456789\",
    \"remarks\": \"Top-up via Eats365 POS\"
}"
Example response:
{
    "data": {
        "id": 1,
        "ref_id": "CREDIT-12345",
        "transaction_timestamp": "2025-05-06T14:30:00.000000Z",
        "amount": "50.00",
        "status": "adopted",
        "pos_provider": "eats365",
        "organisation_id": 1,
        "space_id": 1,
        "credit_id": 101,
        "void_credit_id": null,
        "payload": {
            "terminal": "T001"
        },
        "created_at": "2025-05-06T14:30:01.000000Z",
        "updated_at": "2025-05-06T14:30:01.000000Z"
    }
}
{
    "data": {
        "id": 2,
        "ref_id": "CREDIT-99999",
        "status": "pending",
        "credit_id": null,
        "void_credit_id": null
    }
}
{
    "message": "This action is unauthorized."
}
{
    "message": "The ref id has already been taken.",
    "errors": {
        "ref_id": [
            "The ref id has already been taken."
        ]
    }
}

Void POS Credit

POST
https://explore.pixalink.io.test
/api/posCredit/{posCredit_id}/void
requires authentication

Voids an adopted POS credit record by creating a deduct entry in the customer's credit wallet.

Idempotency: Voiding an already-voided POS credit returns success without creating a duplicate entry.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

posCredit_id
integer
required

The ID of the posCredit.

Example:
1
posCredit
integer
required

The ID of the POS credit to void.

Example:
1

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/posCredit/1/void" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 42,
    \"remarks\": \"Voided per customer request\"
}"
Example response:
{
    "message": "POS credit voided successfully.",
    "data": {
        "id": 202,
        "customer_id": 42,
        "amount": 50,
        "operation": "-",
        "type": "Deduct",
        "remarks": "Voided POS credit #1",
        "created_at": "2025-05-06T15:00:00.000000Z"
    }
}
{
    "message": "This transaction has already been voided.",
    "data": null
}
{
    "message": "Transaction not adopted, nothing to void.",
    "data": null
}
{
    "message": "This action is unauthorized."
}
{
    "message": "Record not found."
}
{
    "message": "A customer ID is required to void this POS credit."
}

POS Transaction

List POS transactions

GET
https://explore.pixalink.io.test
/api/posTransaction
requires authentication

Returns a paginated list of POS transactions for the authenticated organisation. Results can be filtered, sorted and paginated.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[status]
string

Filter by transaction status.

Example:
adopted
filter[space_id]
string

Filter by space UUID.

Example:
1
filter[transaction_time]
string

Filter by transaction date (Y-m-d format).

Example:
2025-05-06
filter[amount_min]
number

Filter by minimum amount.

Example:
50
filter[amount_max]
number

Filter by maximum amount.

Example:
500
filter[ref_id]
string

Filter by reference ID.

Example:
TRX-123
sort
string

Sort by column (prefixed with - for descending). Available options: transaction_time, amount, created_at.

Example:
-transaction_time
include
string

Include related resources. Available options: space.

Example:
space
page
integer

Page number.

Example:
1
per_page
integer

Items per page (max 100).

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/posTransaction?filter%5Bstatus%5D=adopted&filter%5Bspace_id%5D=1&filter%5Btransaction_time%5D=2025-05-06&filter%5Bamount_min%5D=50&filter%5Bamount_max%5D=500&filter%5Bref_id%5D=TRX-123&sort=-transaction_time&include=space&page=1&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "ref_id": "TRX-12345678",
            "transaction_time": "2025-05-06T14:30:00Z",
            "amount": 150,
            "status": "adopted",
            "pos_provider": "provider_name",
            "organisation_id": 1,
            "created_at": "2025-05-06T14:35:00Z",
            "updated_at": "2025-05-06T14:35:00Z",
            "space": {
                "id": "1",
                "name": "Main Store",
                "slug": "main-store"
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/pos-transactions?page=1",
        "last": "{{$baseUrl}}/pos-transactions?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/pos-transactions?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "path": "{{$baseUrl}}/pos-transactions",
        "per_page": 15,
        "to": 15,
        "total": 75
    }
}

Create a new POS transaction

POST
https://explore.pixalink.io.test
/api/posTransaction
requires authentication

This endpoint creates a new POS transaction in the system. If a customer identifier (customer_id or phone_number) is provided, the transaction will be automatically adopted and a corresponding transaction record will be created for the customer.

Partial Refunds: To process a partial refund, send a negative amount. Optionally provide the original_ref_id of the transaction being refunded. The refund will deduct proportional points from the customer's balance.

Blind Refunds: If no original_ref_id is provided with a negative amount (blind refund), points will be deducted using the formula: refund_amount × tier_multiplier (or 1:1 if customer has no tier).

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/posTransaction" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"space_id\": \"1\",
    \"ref_id\": \"TRX-12345678\",
    \"transaction_time\": \"2025-05-06T14:30:00Z\",
    \"amount\": 15000,
    \"payload\": \"{\\\"items\\\": [{\\\"name\\\": \\\"Product A\\\", \\\"quantity\\\": 2, \\\"price\\\": 7500}], \\\"payment_method\\\": \\\"credit_card\\\", \\\"terminal_id\\\": \\\"T001\\\"}\",
    \"customer_id\": 42,
    \"phone_number\": \"+60123456789\",
    \"original_ref_id\": \"TRX-ORIGINAL-001\",
    \"remarks\": \"2x Coffee, 1x Sandwich\"
}"
Example response:
{
    "data": {
        "id": 1,
        "ref_id": "TRX-12345678",
        "transaction_time": "2025-05-06T14:30:00Z",
        "amount": 150,
        "status": "pending",
        "pos_provider": "provider_name",
        "space_id": "1",
        "organisation_id": 1,
        "created_at": "2025-05-06T14:35:00Z",
        "updated_at": "2025-05-06T14:35:00Z"
    }
}
{
    "data": {
        "id": 1,
        "ref_id": "TRX-12345678",
        "transaction_time": "2025-05-06T14:30:00Z",
        "amount": 150,
        "status": "adopted",
        "pos_provider": "provider_name",
        "space_id": "1",
        "organisation_id": 1,
        "created_at": "2025-05-06T14:35:00Z",
        "updated_at": "2025-05-06T14:35:00Z"
    }
}
{
    "data": {
        "id": 2,
        "ref_id": "TRX-REFUND-001",
        "transaction_time": "2025-05-06T15:00:00Z",
        "amount": -50,
        "status": "adopted",
        "pos_provider": "provider_name",
        "space_id": "1",
        "organisation_id": 1,
        "is_refund": true,
        "original_ref_id": "TRX-12345678",
        "refund_details": {
            "original_amount": 150,
            "refund_amount": 50,
            "points_deducted": 50
        },
        "created_at": "2025-05-06T15:00:00Z",
        "updated_at": "2025-05-06T15:00:00Z"
    }
}
{
    "data": {
        "id": 3,
        "ref_id": "TRX-BLIND-REFUND-001",
        "transaction_time": "2025-05-06T15:00:00Z",
        "amount": -50,
        "status": "adopted",
        "pos_provider": "provider_name",
        "space_id": "1",
        "organisation_id": 1,
        "is_refund": true,
        "original_ref_id": null,
        "refund_details": {
            "original_amount": null,
            "refund_amount": 50,
            "points_deducted": 75
        },
        "created_at": "2025-05-06T15:00:00Z",
        "updated_at": "2025-05-06T15:00:00Z"
    }
}
{
    "message": "POS integration not enabled for this organisation"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "ref_id": [
            "The ref id has already been taken."
        ],
        "amount": [
            "The refund amount exceeds the refundable balance."
        ]
    }
}

Void POS Transaction

POST
https://explore.pixalink.io.test
/api/posTransaction/{posTransaction_id}/void
requires authentication

Voids an adopted POS transaction and deducts the exact points that were earned. This generic endpoint works for all POS providers.

The void operation uses the linked transaction_id to deduct the exact amount of points that were earned, accounting for tier multipliers. For example:

  • Customer with 2x Gold tier earns 200 points on $100 purchase
  • Voiding deducts exactly 200 points (not 100)

Idempotency: Attempting to void the same transaction multiple times will return success but only create one void transaction.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

posTransaction_id
integer
required

The ID of the posTransaction.

Example:
1140884
posTransaction
integer
required

The ID of the POS transaction to void.

Example:
123

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/posTransaction/1140884/void" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 456,
    \"remarks\": \"\\\"Transaction voided - customer request\\\"\"
}"
Example response:
{
    "message": "POS transaction voided successfully.",
    "data": {
        "id": 789,
        "customer_id": 456,
        "amount": 200,
        "operation": "-",
        "remarks": "Transaction voided from POS System (Ref: REF-12345)",
        "created_at": "2025-10-25T14:30:00Z"
    }
}
{
    "message": "Transaction not adopted, nothing to void.",
    "data": null
}
{
    "message": "This transaction has already been voided.",
    "data": null
}
{
    "message": "This action is unauthorized."
}
{
    "message": "POS Transaction not found."
}
{
    "message": "The given data was invalid.",
    "errors": {
        "customer_id": [
            "The selected customer does not exist in your organisation."
        ]
    }
}

Paid Membership Types

GET
https://explore.pixalink.io.test
/api/paid_membership_types
requires authentication

Returns a paginated list of paid membership type catalog entries belonging to the authenticated user's organisation. Supports filtering and sorting via query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[is_active]
boolean

Filter by active status.

Example:
true
filter[name]
string

Filter by membership type name (partial match).

Example:
Gold
sort
string

Sort field and direction. Prefix with - for descending. Available fields: sort, name, created_at. Defaults to sort.

Example:
-created_at
per_page
integer

Number of records per page. Defaults to 15.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/paid_membership_types?filter%5Bis_active%5D=1&filter%5Bname%5D=Gold&sort=-created_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "organisation_id": 1,
            "name": "VIP Gold",
            "description": "Priority support and birthday rewards.",
            "pricing_options": [
                {
                    "cycle": "monthly",
                    "price": 3500
                },
                {
                    "cycle": "yearly",
                    "price": 35000
                }
            ],
            "benefits": [
                {
                    "icon": "heroicon-o-star",
                    "heading": "Priority Support",
                    "description": "Get priority customer support"
                }
            ],
            "sort": 1,
            "is_active": true,
            "created_at": "2025-01-31T21:16:49.000000Z",
            "updated_at": "2025-01-31T21:16:49.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "...",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}
GET
https://explore.pixalink.io.test
/api/paid_membership_types/{id}
requires authentication

Retrieves a single paid membership type by ID. Cross-organisation access returns 404.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the paid membership type.

Example:
1
paid_membership_type
integer
required

The ID of the paid membership type.

Example:
1

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/paid_membership_types/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "organisation_id": 1,
        "name": "VIP Gold",
        "description": "Priority support and birthday rewards.",
        "pricing_options": [
            {
                "cycle": "monthly",
                "price": 3500
            }
        ],
        "benefits": [],
        "sort": 1,
        "is_active": true,
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    }
}
{
    "message": "Record not found"
}

Payments

List Payments

GET
https://explore.pixalink.io.test
/api/payments
requires authentication

Get a paginated list of payments and refunds belonging to the authenticated user's organisation. Results can be filtered, sorted and expanded with related data through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[type]
string

Filter by record type. Available values: payment, refund.

Example:
payment
filter[status]
integer

Filter by payment status code (e.g. 0 = pending, 1 = success, 2 = failed).

Example:
1
filter[method]
string

Filter by payment method (e.g. commerce_pay, manual, credit).

Example:
commerce_pay
filter[payable_type]
string

Filter by the fully-qualified class of what was paid for.

Example:
App\Models\Reservation
filter[created_at]
string

Filter by creation date with operators.

Example:
>2024-01-01
filter[completed_at]
string

Filter by completion date with operators.

Example:
>2024-01-01
sort
string

Sort field. Allowed: created_at, completed_at, amount. Use - for descending.

Example:
-created_at
include
string

Comma-separated relationships to include. Allowed: refunds, refundingPayment.

Example:
refunds
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/payments?filter%5Btype%5D=payment&filter%5Bstatus%5D=1&filter%5Bmethod%5D=commerce_pay&filter%5Bpayable_type%5D=App%5CModels%5CReservation&filter%5Bcreated_at%5D=%3E2024-01-01&filter%5Bcompleted_at%5D=%3E2024-01-01&sort=-created_at&include=refunds&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "type": "payment",
            "method": "commerce_pay",
            "reference_id": "TXN-1234567890",
            "amount": 150,
            "currency_code": "MYR",
            "status": 1,
            "is_manual": false,
            "payment_type": null,
            "source": null,
            "attempted_at": "2025-01-01T00:00:00+00:00",
            "completed_at": "2025-01-01T00:01:00+00:00",
            "failed_at": null,
            "failure_reason": null,
            "created_at": "2025-01-01T00:00:00+00:00"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "per_page": 15,
        "total": 1
    }
}
{
    "data": [],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "per_page": 15,
        "total": 0
    }
}
{
    "message": "Unauthenticated."
}
{
    "message": "This action is unauthorized."
}

Show Payment

GET
https://explore.pixalink.io.test
/api/payments/{id}
requires authentication

Retrieve detailed information about a specific payment or refund.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the payment.

Example:
1
payment
integer
required

The ID of the payment.

Example:
1

Query Parameters

include
string

Comma-separated relationships to include. Allowed: refunds, refundingPayment.

Example:
refunds

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/payments/1?include=refunds" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "type": "payment",
        "method": "commerce_pay",
        "reference_id": "TXN-1234567890",
        "amount": 150,
        "currency_code": "MYR",
        "status": 1,
        "is_manual": false,
        "payment_type": null,
        "source": null,
        "attempted_at": "2025-01-01T00:00:00+00:00",
        "completed_at": "2025-01-01T00:01:00+00:00",
        "failed_at": null,
        "failure_reason": null,
        "created_at": "2025-01-01T00:00:00+00:00"
    }
}
{
    "message": "Unauthenticated."
}
{
    "message": "This action is unauthorized."
}
{
    "message": "Record not found."
}

Plans

List Plans

GET
https://explore.pixalink.io.test
/api/plans
requires authentication

Returns a paginated list of active subscription plans, including their prices.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter by plan name (partial match).

Example:
Premium
sort
string

Sort field. Allowed: id, name, created_at.

Example:
-id
per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/plans?filter%5Bname%5D=Premium&sort=-id&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Premium",
            "description": "Full access to all features",
            "is_active": true,
            "features": {
                "loyalty_enabled": true,
                "credits_enabled": true,
                "tiering_enabled": true,
                "max_spaces": 3,
                "max_customers": 10000
            },
            "prices": [
                {
                    "id": 1,
                    "currency": "MYR",
                    "billing_period": "monthly",
                    "amount": 350,
                    "stripe_price_id": "price_1ABC",
                    "is_active": true,
                    "description": null
                }
            ],
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Show Plan

GET
https://explore.pixalink.io.test
/api/plans/{id}
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The plan ID.

Example:
1

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/plans/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Premium",
        "features": {
            "loyalty_enabled": true
        },
        "prices": []
    }
}
{
    "message": "No query results for model [Plan] 1"
}

Reward Validation

APIs for validating reward redemption codes

Validate Reward Code

POST
https://explore.pixalink.io.test
/api/customer_rewards/validate
requires authentication

Validates a 6-digit reward redemption code and returns validation status along with complete reward details. This endpoint is designed for cashiers and POS systems to verify reward codes before processing redemptions.

The validation process checks:

  • Code format (must be exactly 6 digits)
  • Code existence in the system
  • Code expiration status
  • Whether the code has already been used
  • Organisation-level multi-tenancy

The response includes the full reward object with properties field containing POS integration settings. For iVend POS: Check reward.properties.ivend.enabled to determine if the reward can be processed. Use reward.properties.ivend.amount to apply the discount amount.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/customer_rewards/validate" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"code\": \"123456\",
    \"organisation_id\": 123
}"
Example response:
{
    "valid": true,
    "message": "Code is valid",
    "data": {
        "id": 101,
        "status": "Pending",
        "code": "123456",
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "used_at": null,
        "customer_id": 42,
        "reward_id": 5,
        "customer": {
            "id": 42,
            "name": "John Doe",
            "phone_number": "+601234567890",
            "email": "john@example.com",
            "current_point": 2500,
            "current_credits": 150
        },
        "reward": {
            "id": 5,
            "name": "Free Coffee",
            "description": "Complimentary coffee of your choice",
            "terms": "Valid at all outlets. One redemption per visit.",
            "is_active": true,
            "start_at": null,
            "end_at": null,
            "valid_days": 30,
            "amount": 100,
            "point_is_active": true,
            "credit_is_active": false,
            "credit_amount": null,
            "credit_earn_point": false,
            "available_currency_types": [
                "point"
            ],
            "allow_customer_self_reward": true,
            "is_one_time_reward": false,
            "is_direct_link_accessible": false,
            "is_redeemable": true,
            "is_custom_valid_days": true,
            "is_limit_total_availability": false,
            "total_availability": null,
            "total_redeemed": 15,
            "cover": "gift",
            "automations": [],
            "notification_settings": {},
            "properties": {
                "ivend": {
                    "enabled": true,
                    "type": "amount",
                    "amount": 5
                }
            },
            "created_at": "2024-01-15T08:30:00.000000Z",
            "updated_at": "2024-02-10T10:45:00.000000Z"
        }
    }
}
{
    "message": "Organisation not found"
}
{
    "valid": false,
    "message": "Code has expired",
    "error_code": "CODE_EXPIRED"
}
{
    "valid": false,
    "message": "Code has already been used",
    "error_code": "CODE_ALREADY_USED"
}
{
    "valid": false,
    "message": "Invalid redemption code",
    "error_code": "CODE_NOT_FOUND"
}
{
    "valid": false,
    "message": "Code must be exactly 6 digits",
    "error_code": "INVALID_FORMAT"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "code": [
            "Code must be exactly 6 digits."
        ],
        "organisation_id": [
            "Organisation ID is required."
        ]
    }
}

Rewards

List Rewards

GET
https://explore.pixalink.io.test
/api/rewards
requires authentication

Returns a paginated list of rewards belonging to the authenticated user's organisation spaces.
Supports filtering, sorting and relationship inclusion through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • space
  • customerRewards
  • rewardVouchers
  • inviterReferralItem
  • inviteeReferralItem
  • rewardBundleItems
  • pendingRewardVouchers
Example:
space,customerRewards
filter[space_id]
integer

Filter by space ID.

Example:
1
filter[is_active]
boolean

Filter by active status.

Example:
true
filter[is_redeemable]
boolean

Filter by redeemable status.

Example:
true
filter[is_one_time_reward]
boolean

Filter by one-time reward status.

Example:
false
filter[allow_customer_self_reward]
boolean

Filter by self-reward permission.

Example:
true
filter[point_is_active]
boolean

Filter by point redemption availability.

Example:
true
filter[credit_is_active]
boolean

Filter by credit redemption availability.

Example:
true
filter[available]
boolean

Filter by availability (considers active status and date range).

Example:
true
filter[name]
string

Filter by reward name (partial match).

Example:
Birthday
sort
string

Sort field and direction. Note: Prefix with - for descending order. Available sort fields:

  • name
  • start_at
  • end_at
  • created_at
  • amount
Example:
-created_at
per_page
integer

Number of records per page. Defaults to 15.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/rewards?include=space%2CcustomerRewards&filter%5Bspace_id%5D=1&filter%5Bis_active%5D=1&filter%5Bis_redeemable%5D=1&filter%5Bis_one_time_reward%5D=&filter%5Ballow_customer_self_reward%5D=1&filter%5Bpoint_is_active%5D=1&filter%5Bcredit_is_active%5D=1&filter%5Bavailable%5D=1&filter%5Bname%5D=Birthday&sort=-created_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Birthday Reward",
            "description": "Special reward for customer birthdays",
            "terms": "Valid for 30 days from issue",
            "is_active": true,
            "start_at": "2025-01-01T00:00:00.000000Z",
            "end_at": "2025-12-31T23:59:59.000000Z",
            "valid_days": 30,
            "amount": 1000,
            "allow_customer_self_reward": false,
            "is_one_time_reward": true,
            "is_direct_link_accessible": false,
            "is_redeemable": true,
            "is_custom_valid_days": true,
            "is_limit_total_availability": true,
            "total_availability": 100,
            "total_redeemed": 0,
            "cover": "gift",
            "automations": [],
            "notification_settings": {
                "new_reward": {
                    "is_enabled": true,
                    "message": "You've received a birthday reward!"
                }
            },
            "properties": {
                "ivend": {
                    "enabled": true,
                    "type": "amount",
                    "amount": 10
                }
            },
            "created_at": "2025-01-31T21:16:49.000000Z",
            "updated_at": "2025-01-31T21:16:49.000000Z"
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/rewards?page=1",
        "last": "{{$baseUrl}}/api/rewards?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "{{$baseUrl}}/api/rewards",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Create Reward

POST
https://explore.pixalink.io.test
/api/rewards
requires authentication

Creates a new reward in the system.
The reward will be associated with the specified space in the authenticated user's organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/rewards" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Birthday Reward\",
    \"description\": \"Special reward for customer birthdays\",
    \"terms\": \"Valid for 30 days from issue\",
    \"space_id\": 1,
    \"is_active\": true,
    \"start_at\": \"2025-01-01\",
    \"end_at\": \"2025-12-31\",
    \"is_redeemable\": true,
    \"is_custom_valid_days\": true,
    \"valid_days\": 30,
    \"amount\": 1000,
    \"point_is_active\": true,
    \"credit_is_active\": true,
    \"credit_amount\": \"10.50\",
    \"credit_earn_point\": false,
    \"allow_customer_self_reward\": true,
    \"is_one_time_reward\": true,
    \"is_direct_link_accessible\": false,
    \"is_limit_total_availability\": true,
    \"total_availability\": 100,
    \"cover\": \"gift\",
    \"notification_settings\": {
        \"new_reward\": {
            \"is_enabled\": false,
            \"message\": \"Hi {{NAME}}, you have received a new reward from {{SPACE_NAME}}!\"
        },
        \"expired_reward\": {
            \"is_enabled\": true,
            \"message\": \"Hi {{NAME}}, your reward has expired.\"
        },
        \"expiring_reward\": {
            \"is_enabled\": true,
            \"message\": \"Hi {{NAME}}, your reward will expire soon!\",
            \"send_notification_before\": \"7\"
        }
    }
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "Birthday Reward",
        "description": "Special reward for customer birthdays",
        "terms": "Valid for 30 days from issue",
        "is_active": true,
        "start_at": "2025-01-01T00:00:00.000000Z",
        "end_at": "2025-12-31T23:59:59.000000Z",
        "valid_days": 30,
        "amount": 1000,
        "allow_customer_self_reward": false,
        "is_one_time_reward": true,
        "is_direct_link_accessible": false,
        "is_redeemable": true,
        "is_custom_valid_days": true,
        "is_limit_total_availability": true,
        "total_availability": 100,
        "total_redeemed": 0,
        "cover": "gift",
        "automations": [],
        "notification_settings": {
            "new_reward": {
                "is_enabled": true,
                "message": "You've received a birthday reward!"
            }
        },
        "properties": {
            "ivend": {
                "enabled": true,
                "type": "amount",
                "amount": 10
            }
        },
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    },
    "message": "Reward created successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name field is required."
        ],
        "space_id": [
            "The selected space id is invalid."
        ],
        "amount": [
            "The amount must be at least 0."
        ]
    }
}

Show Reward Details

GET
https://explore.pixalink.io.test
/api/rewards/{id}
requires authentication

Retrieves detailed information about a specific reward, including any requested relationships.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reward.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • space
  • customerRewards
  • rewardVouchers
  • inviterReferralItem
  • inviteeReferralItem
  • rewardBundleItems
  • pendingRewardVouchers
Example:
space,customerRewards

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/rewards/1?include=space%2CcustomerRewards" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Birthday Reward",
        "description": "Special reward for customer birthdays",
        "terms": "Valid for 30 days from issue",
        "is_active": true,
        "start_at": "2025-01-01T00:00:00.000000Z",
        "end_at": "2025-12-31T23:59:59.000000Z",
        "valid_days": 30,
        "amount": 1000,
        "allow_customer_self_reward": false,
        "is_one_time_reward": true,
        "is_direct_link_accessible": false,
        "is_redeemable": true,
        "is_custom_valid_days": true,
        "is_limit_total_availability": true,
        "total_availability": 100,
        "total_redeemed": 0,
        "cover": "gift",
        "automations": [],
        "notification_settings": {
            "new_reward": {
                "is_enabled": true,
                "message": "You've received a birthday reward!"
            }
        },
        "properties": {
            "ivend": {
                "enabled": true,
                "type": "amount",
                "amount": 10
            }
        },
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    }
}
{
    "message": "Record not found"
}

Update Reward

PUT
PATCH
https://explore.pixalink.io.test
/api/rewards/{id}
requires authentication

Updates an existing reward's information.
All fields are optional.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reward.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/rewards/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Birthday Reward\",
    \"description\": \"Special reward for customer birthdays\",
    \"terms\": \"Valid for 30 days from issue\",
    \"space_id\": 1,
    \"is_active\": true,
    \"start_at\": \"2025-01-01\",
    \"end_at\": \"2025-12-31\",
    \"is_redeemable\": true,
    \"is_custom_valid_days\": true,
    \"valid_days\": 30,
    \"amount\": 1000,
    \"point_is_active\": true,
    \"credit_is_active\": true,
    \"credit_amount\": \"10.50\",
    \"credit_earn_point\": false,
    \"allow_customer_self_reward\": true,
    \"is_one_time_reward\": true,
    \"is_direct_link_accessible\": false,
    \"is_limit_total_availability\": true,
    \"total_availability\": 100,
    \"cover\": \"gift\",
    \"notification_settings\": {
        \"new_reward\": {
            \"is_enabled\": false,
            \"message\": \"laboriosam\"
        },
        \"expired_reward\": {
            \"is_enabled\": true,
            \"message\": \"Hi {{NAME}}, your reward has expired.\"
        },
        \"expiring_reward\": {
            \"is_enabled\": true,
            \"message\": \"Hi {{NAME}}, your reward will expire soon!\",
            \"send_notification_before\": \"7\"
        }
    }
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "Birthday Reward",
        "description": "Special reward for customer birthdays",
        "terms": "Valid for 30 days from issue",
        "is_active": true,
        "start_at": "2025-01-01T00:00:00.000000Z",
        "end_at": "2025-12-31T23:59:59.000000Z",
        "valid_days": 30,
        "amount": 1000,
        "allow_customer_self_reward": false,
        "is_one_time_reward": true,
        "is_direct_link_accessible": false,
        "is_redeemable": true,
        "is_custom_valid_days": true,
        "is_limit_total_availability": true,
        "total_availability": 100,
        "total_redeemed": 0,
        "cover": "gift",
        "automations": [],
        "notification_settings": {
            "new_reward": {
                "is_enabled": true,
                "message": "You've received a birthday reward!"
            }
        },
        "properties": {
            "ivend": {
                "enabled": true,
                "type": "amount",
                "amount": 10
            }
        },
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    },
    "message": "Reward updated successfully"
}
{
    "message": "Record not found"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name field is required."
        ],
        "space_id": [
            "The selected space id is invalid."
        ],
        "amount": [
            "The amount must be at least 0."
        ]
    }
}

Delete Reward

DELETE
https://explore.pixalink.io.test
/api/rewards/{id}
requires authentication

Deletes a reward from the system.
Only rewards that haven't been assigned to any customers can be deleted.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reward.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/rewards/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
[Empty response]
{
    "message": "Record not found"
}
{
    "message": "Cannot delete reward that has been assigned to customers"
}

Reward Voucher

Third-party reward vouchers allow businesses to integrate external voucher codes (like e-commerce platform vouchers) into their loyalty program. These vouchers can be imported in bulk, managed within the system, and distributed to customers as rewards. Each voucher has a unique code and can be tracked through various states including available, used, expired, and pending. This feature enables seamless integration of external reward partnerships while maintaining full tracking and validation capabilities.


List reward vouchers

GET
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers
requires authentication

Get a paginated list of vouchers for a specific reward.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward.

Example:
10

Body Parameters

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/rewards/10/vouchers" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"Active\",
    \"search\": \"REWARD123\",
    \"page\": 1,
    \"per_page\": 15
}"
Example response:
{
    "data": [
        {
            "id": 1,
            "code": "REWARD123",
            "status": "available",
            "expired_at": "2024-12-31T23:59:59Z",
            "given_at": null,
            "used_at": null,
            "customer_reward": {
                "customer": {
                    "id": 1,
                    "name": "John Doe",
                    "phone_number": "+1234567890"
                }
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/rewards/{{reward_id}}/vouchers?page=1",
        "last": "{{$baseUrl}}/api/rewards/{{reward_id}}/vouchers?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "last_page": 1,
        "per_page": 15,
        "total": 1
    }
}
{
    "message": "Record not found."
}

Create reward voucher

POST
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers
requires authentication

Creates a reward voucher for a specific reward. The voucher is initially created in a pending status, which means it has been generated but not yet assigned. The voucher will remain in this state until it is given to a recipient or further processed.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward.

Example:
2

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/rewards/2/vouchers" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"code\": \"REWARD123XYZ\",
    \"expired_at\": \"2024-12-31T23:59:59Z\"
}"
Example response:
{
    "id": 1,
    "code": "REWARD123",
    "status": "available",
    "expired_at": "2024-12-31T23:59:59Z",
    "given_at": null,
    "used_at": null
}

Show reward voucher details

GET
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers/{id}
requires authentication

Retrieve detailed information about a specific reward voucher. This endpoint allows fetching a single voucher with optional related resources.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The unique identifier of the reward.

Example:
1
id
integer
required

The unique identifier of the voucher.

Example:
42

Query Parameters

include
string

Optional related resources to include. Possible values: customerReward, customerReward.customer, reward

Example:
customerReward,reward

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/rewards/1/vouchers/42?include=customerReward%2Creward" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "id": 1,
    "code": "REWARD123",
    "status": "available",
    "expired_at": "2024-12-31T23:59:59Z",
    "given_at": null,
    "used_at": null,
    "customer_reward": {
        "id": 12,
        "status": "pending"
    },
    "reward": {
        "id": 1,
        "name": "Loyalty Discount",
        "description": "10% off next purchase"
    }
}
{
    "message": "Record not found."
}

Update reward voucher status

PUT
PATCH
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers/{id}
requires authentication

Update the status of a specific voucher.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward.

Example:
20
id
integer
required

The ID of the voucher.

Example:
5

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/rewards/20/vouchers/5" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"used\"
}"
Example response:
{
    "id": 1,
    "code": "REWARD123",
    "status": "used",
    "expired_at": "2024-12-31T23:59:59Z",
    "given_at": "2024-02-09T10:00:00Z",
    "used_at": "2024-02-09T12:00:00Z"
}
{
    "message": "Record not found."
}

Delete reward voucher

DELETE
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers/{id}
requires authentication

Delete a specific voucher.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward.

Example:
9
id
integer
required

The ID of the voucher.

Example:
20
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/rewards/9/vouchers/20" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
[Empty response]
{
    "message": "Record not found."
}

Bulk Update Reward Vouchers

POST
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers/bulk-update
requires authentication

Updates the status of multiple reward vouchers asynchronously. The operation is queued as a background job and processed in chunks of 100 records. This endpoint is rate limited to 10 requests per minute.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward these vouchers belong to.

Example:
1

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/rewards/1/vouchers/bulk-update" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"voucher_codes\": [
        \"REWARD123\"
    ],
    \"voucher_ids\": [
        1
    ],
    \"status\": \"Used\"
}"
Example response:
{
    "message": "Bulk voucher update has been queued and will be processed shortly",
    "updated_count": 3
}
{
    "message": "Record not found."
}
{
    "message": "Validation failed",
    "errors": {
        "voucher_codes": [
            "Either voucher_codes or voucher_ids must be provided."
        ]
    }
}
{
    "message": "Too Many Attempts."
}

Bulk import vouchers

POST
https://explore.pixalink.io.test
/api/rewards/{reward_id}/vouchers/bulk-import
requires authentication

Import multiple vouchers for a reward asynchronously. The operation is queued and processed in chunks of 100 records. Limited to 10,000 vouchers per request and rate limited to 10 requests per minute.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

reward_id
integer
required

The ID of the reward.

Example:
2

Body Parameters

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/rewards/2/vouchers/bulk-import" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"vouchers\": [
        {
            \"code\": \"REWARD123\",
            \"expired_at\": \"2024-12-31T23:59:59Z\"
        }
    ],
    \"auto_reassign\": false
}"
Example response:
{
    "message": "Bulk voucher import has been queued and will be processed shortly"
}
{
    "message": "Record not found."
}
{
    "message": "The given data was invalid.",
    "errors": {
        "vouchers": [
            "The vouchers must not have more than 10000 items."
        ],
        "vouchers.*.code": [
            "The vouchers.0.expired_at has already been taken."
        ],
        "vouchers.*.expired_at": [
            "The vouchers.0.expired_at must be a date after now."
        ]
    }
}
{
    "message": "Too Many Attempts."
}

Roles

List Roles

GET
https://explore.pixalink.io.test
/api/roles
requires authentication

Returns a paginated list of all available roles.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter by role name (partial match).

Example:
Admin
sort
string

Sort field. Allowed: id, name, created_at.

Example:
-id
per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/roles?filter%5Bname%5D=Admin&sort=-id&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Super Admin",
            "guard_name": "web",
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Show Role

GET
https://explore.pixalink.io.test
/api/roles/{id}
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The role ID.

Example:
1

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/roles/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Admin",
        "guard_name": "web"
    }
}
{
    "message": "No query results for model [Role] 1"
}

Spaces

List Spaces

GET
https://explore.pixalink.io.test
/api/spaces
requires authentication

Returns a paginated list of spaces belonging to the authenticated user's organisation.
Supports filtering, sorting and relationship inclusion through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • category (Space category details)
  • address (Physical address details)
Example:
category,address
filter[visibility]
string

Filter by visibility status. Available options:

  • public (Listed and viewable by anyone)
  • private (Not listed, viewable with link)
  • hidden (Not listed, cannot be searched)
  • draft (Not listed, cannot be searched)
Example:
public
filter[category_id]
integer

Filter by category ID.

Example:
1
filter[name]
string

Filter by space name (partial match).

Example:
Coworking
filter[description]
string

Filter by space description (partial match).

Example:
modern
filter[email]
string

Filter by space email (partial match).

Example:
space@example.com
filter[organisation_id]
integer

Filter by organisation ID.

Example:
1
filter[has_posts]
boolean

Filter spaces that have posts.

Example:
true
sort
string

Sort field and direction. Available fields:

  • name (Sort by space name)
  • created_at (Sort by creation date)
  • updated_at (Sort by last update)
  • visits (Sort by number of visits) Default: -created_at
Example:
-visits
per_page
integer

Number of records per page. Default: 15.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/spaces?include=category%2Caddress&filter%5Bvisibility%5D=public&filter%5Bcategory_id%5D=1&filter%5Bname%5D=Coworking&filter%5Bdescription%5D=modern&filter%5Bemail%5D=space%40example.com&filter%5Borganisation_id%5D=1&filter%5Bhas_posts%5D=1&sort=-visits&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "uuid": "f2d75bf6-3cb8-305c-8f70-f71fe697cba3",
            "name": "Modern Coworking Space",
            "slug": "modern-coworking-space",
            "matterport_model_id": null,
            "description": "A modern coworking space in the heart of the city",
            "visibility": "public",
            "email": "space@example.com",
            "phone_number": "+60123456789",
            "website": "{{$baseUrl}}/spaces/modern-coworking",
            "social_media": [
                {
                    "name": "Twitter",
                    "username": "@modernspace"
                },
                {
                    "name": "Facebook",
                    "username": "modernspacekl"
                }
            ],
            "organisation_id": 1,
            "category_id": 2,
            "visits": 1250,
            "created_at": "2024-01-15T08:00:00Z",
            "updated_at": "2024-02-08T14:30:00Z",
            "deleted_at": null,
            "address": {
                "id": 1,
                "address_line_1": "123 Jalan Sultan Ismail",
                "address_line_2": "Level 23",
                "postal_code": "50250",
                "city": "Kuala Lumpur",
                "state": "Wilayah Persekutuan",
                "country": "Malaysia"
            },
            "category": {
                "id": 2,
                "name": "Coworking Space",
                "slug": "coworking-space"
            },
            "links": {
                "public_url": "{{$baseUrl}}/spaces/modern-coworking-space"
            }
        },
        {
            "id": 2,
            "name": "Creative Studio",
            "slug": "creative-studio",
            "matterport_model_id": "abc123xyz",
            "description": "A creative studio space perfect for photographers and content creators",
            "visibility": "public",
            "email": "studio@example.com",
            "phone_number": "+60123456790",
            "website": "{{$baseUrl}}/spaces/creative-studio",
            "social_media": [
                {
                    "name": "Instagram",
                    "username": "@creativestudiomy"
                }
            ],
            "organisation_id": 1,
            "category_id": 3,
            "visits": 890,
            "created_at": "2024-01-20T10:00:00Z",
            "updated_at": "2024-02-07T16:45:00Z",
            "deleted_at": null,
            "address": {
                "id": 2,
                "address_line_1": "45 Jalan Telawi",
                "address_line_2": null,
                "postal_code": "59100",
                "city": "Bangsar",
                "state": "Kuala Lumpur",
                "country": "Malaysia"
            },
            "category": {
                "id": 3,
                "name": "Studio Space",
                "slug": "studio-space"
            },
            "links": {
                "public_url": "{{$baseUrl}}/spaces/creative-studio"
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/v1/spaces?page=1",
        "last": "{{$baseUrl}}/api/v1/spaces?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/api/v1/spaces?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "path": "{{$baseUrl}}/api/v1/spaces",
        "per_page": 15,
        "to": 15,
        "total": 68
    }
}

Create Space

POST
https://explore.pixalink.io.test
/api/spaces
requires authentication

Creates a new space in the system.
The space will be associated with the authenticated user's organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/spaces" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Modern Coworking Space\",
    \"description\": \"A modern coworking space in the heart of the city\",
    \"visibility\": \"Public\",
    \"email\": \"space@example.com\",
    \"phone_number\": \"+60123456789\",
    \"website\": \"{{$baseUrl}}\",
    \"category_id\": 1,
    \"social_media\": [
        \"qui\"
    ],
    \"address\": [
        \"aliquam\"
    ],
    \"tags\": [
        \"Coworking\",
        \"24\\/7\"
    ],
    \"classification\": [
        \"Premium\",
        \"Featured\"
    ]
}"
Example response:
{
    "data": {
        "id": 1,
        "uuid": "f2d75bf6-3cb8-305c-8f70-f71fe697cba3",
        "name": "Modern Coworking Space",
        "slug": "modern-coworking-space",
        "matterport_model_id": null,
        "description": "A modern coworking space in the heart of the city offering flexible workspace solutions for professionals and teams",
        "visibility": "public",
        "email": "space@example.com",
        "phone_number": "+60123456789",
        "website": "https://pixalink.io/spaces/modern-coworking",
        "social_media": [
            {
                "name": "Twitter",
                "username": "@modernspace"
            },
            {
                "name": "Facebook",
                "username": "modernspacekl"
            },
            {
                "name": "Instagram",
                "username": "@modernspace.kl"
            }
        ],
        "organisation_id": 1,
        "category_id": 2,
        "visits": 0,
        "created_at": "2024-02-08T15:00:00Z",
        "updated_at": "2024-02-08T15:00:00Z",
        "deleted_at": null,
        "address": {
            "id": 1,
            "address_line_1": "123 Jalan Sultan Ismail",
            "address_line_2": "Level 23",
            "postal_code": "50250",
            "city": "Kuala Lumpur",
            "state": "Wilayah Persekutuan",
            "country": "Malaysia"
        },
        "links": {
            "public_url": "{{$baseUrl}}/spaces/modern-coworking-space"
        }
    }
}
{
   "message": "The given data was invalid.",
   "errors": {
     "name": [
       "The name field is required."
     ],
     "description": [
       "The description field is required."
     ],
     "visibility": [
       "The visibility field is required.",
       "The selected visibility is invalid."
     ],
     "category_id": [
       "The category id field is required.",
       "The selected category id is invalid."
     ],
     "address.address_line_1": [
       "The address line 1 field is required."
     ],
     "address.postal_code": [
       "The postal code must be 5 digits."
     ],
     "address.country": [
       "The selected country is invalid."
     ],
     "phone_number": [
       "The phone number format is invalid."
     ]
   }

Show Space Details

GET
https://explore.pixalink.io.test
/api/spaces/{id}
requires authentication

Retrieves detailed information about a specific space, including any requested relationships.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the space.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • category
  • address
  • posts
  • widgets
  • activeWidgets
  • activeCalendars
Example:
category,address

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/spaces/1?include=category%2Caddress" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "uuid": "f2d75bf6-3cb8-305c-8f70-f71fe697cba3",
        "name": "Modern Coworking Space",
        "slug": "modern-coworking-space",
        "matterport_model_id": null,
        "description": "A modern coworking space in the heart of the city",
        "visibility": "public",
        "email": "space@example.com",
        "phone_number": "+60123456789",
        "website": "{{$baseUrl}}",
        "social_media": [
            {
                "name": "Twitter",
                "username": "@modernspace"
            }
        ],
        "tags": [
            "Coworking",
            "24/7"
        ],
        "classification": [
            "Premium",
            "Featured"
        ],
        "category_id": 1,
        "organisation_id": 1,
        "visits": 150,
        "created_at": "2024-02-02T12:00:00Z",
        "updated_at": "2024-02-02T12:00:00Z",
        "address": {
            "id": 1,
            "address_line_1": "123 Main Street",
            "address_line_2": "Suite 45",
            "postal_code": "50450",
            "city": "Petaling Jaya",
            "state": "Selangor",
            "country": "Malaysia"
        },
        "media": {
            "preview": {
                "url": "{{$baseUrl}}/media/preview.jpg",
                "type": "image"
            },
            "featured_image": {
                "url": "{{$baseUrl}}/media/featured.jpg"
            },
            "gallery": [
                {
                    "url": "{{$baseUrl}}/media/gallery1.jpg"
                }
            ],
            "logo": {
                "url": "{{$baseUrl}}/media/logo.jpg"
            }
        }
    }
}
{
    "message": "Record not found"
}

Update Space

PUT
PATCH
https://explore.pixalink.io.test
/api/spaces/{id}
requires authentication

Updates an existing space's information.
All fields are optional.
Omitted fields will retain their current values.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the space.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/spaces/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Modern Coworking Space\",
    \"description\": \"A modern coworking space in the heart of the city\",
    \"visibility\": \"Public\",
    \"email\": \"space@example.com\",
    \"phone_number\": \"ipsum\",
    \"website\": \"{{$baseUrl}}\",
    \"category_id\": 1,
    \"social_media\": [
        \"amet\"
    ],
    \"address\": [
        \"quasi\"
    ],
    \"tags\": [
        \"Coworking\",
        \"24\\/7\"
    ],
    \"classification\": [
        \"Premium\",
        \"Featured\"
    ]
}"
Example response:
{
    "data": {
        "id": 1,
        "uuid": "f2d75bf6-3cb8-305c-8f70-f71fe697cba3",
        "name": "Modern Coworking Space",
        "slug": "modern-coworking-space",
        "matterport_model_id": null,
        "description": "A modern coworking space in the heart of the city",
        "visibility": "public",
        "email": "space@example.com",
        "phone_number": "+60123456789",
        "website": "{{$baseUrl}}",
        "social_media": [
            {
                "name": "Twitter",
                "username": "@modernspace"
            }
        ],
        "tags": [
            "Coworking",
            "24/7"
        ],
        "classification": [
            "Premium",
            "Featured"
        ],
        "category_id": 1,
        "organisation_id": 1,
        "visits": 150,
        "created_at": "2024-02-02T12:00:00Z",
        "updated_at": "2024-02-02T12:00:00Z"
    }
}
{
    "message": "Record not found"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "email": [
            "The email must be a valid email address."
        ],
        "phone_number": [
            "The phone number must be a valid phone number."
        ],
        "visibility": [
            "The selected visibility is invalid."
        ],
        "address.country": [
            "The selected country is invalid. Only Malaysia and Singapore are allowed."
        ],
        "media.preview": [
            "The preview must be an image file of type: png, jpg, jpeg, ico."
        ]
    }
}

Delete Space

DELETE
https://explore.pixalink.io.test
/api/spaces/{id}
requires authentication

Deletes a space and all its associated data including:

  • Address
  • Media (preview, gallery, logo)
  • Tags and classifications
  • Widgets
  • Posts
  • POS integration settings

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the space.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/spaces/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
[Empty response]
{
    "message": "You are not authorized to delete this space"
}
{
    "message": "Record not found"
}

Transactions

List Transactions

GET
https://explore.pixalink.io.test
/api/transactions
requires authentication

Get a paginated list of transactions for the organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[customer_id]
integer

Filter by customer ID.

Example:
1
filter[type]
string

Filter by transaction type. Available types:

  • Purchase: Points earned from purchases
  • Review: Points earned from reviews
  • Referral: Points earned from referrals
  • Point Reward Redeem: Points spent on reward redemption
Example:
Purchase
filter[space_id]
integer

Filter by space ID.

Example:
1
filter[amount]
string

Filter by amount with operators (>, <, =).

Example:
>100
filter[created_at]
string

Filter by date with operators.

Example:
>2024-01-01
filter[updated_at]
string

Filter by updated date with operators.

Example:
>2024-01-01
sort
string

Sort field (created_at, amount). Use -field for descending.

Example:
-created_at
include
string

Include relationships (customer, reward, space, customerRewards).

Example:
customer,reward,customerRewards
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/transactions?filter%5Bcustomer_id%5D=1&filter%5Btype%5D=Purchase&filter%5Bspace_id%5D=1&filter%5Bamount%5D=%3E100&filter%5Bcreated_at%5D=%3E2024-01-01&filter%5Bupdated_at%5D=%3E2024-01-01&sort=-created_at&include=customer%2Creward%2CcustomerRewards&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "amount": 1000,
            "valid_amount": 1000,
            "operation": "+",
            "type": "Purchase",
            "remarks": "Purchase at Store #123",
            "customer_id": 1,
            "space_id": 1,
            "reward_id": null,
            "custom_properties": {
                "purchase_amount": 1000,
                "receipt_number": "R12345"
            },
            "expired_at": "2024-02-10T23:59:59.000000Z",
            "created_at": "2024-02-09T10:00:00.000000Z",
            "updated_at": "2024-02-09T10:00:00.000000Z",
            "customer": {
                "id": 1,
                "name": "John Smith",
                "email": "john.smith@example.com",
                "phone_number": "+60123456789",
                "current_point": 2500,
                "current_credits": 150
            }
        },
        {
            "id": 2,
            "amount": 500,
            "valid_amount": 500,
            "operation": "-",
            "type": "Point_Reward_Redeem",
            "remarks": "Reward: Free Coffee",
            "customer_id": 1,
            "space_id": 1,
            "reward_id": 5,
            "custom_properties": null,
            "expired_at": null,
            "created_at": "2024-02-08T15:30:00.000000Z",
            "updated_at": "2024-02-08T15:30:00.000000Z",
            "reward": {
                "id": 5,
                "name": "Free Coffee",
                "amount": 500,
                "description": "Redeem a free coffee at any of our locations"
            },
            "customerRewards": [
                {
                    "id": 1,
                    "status": "Used",
                    "code": null,
                    "expired_at": "2024-02-08T15:30:00.000000Z",
                    "used_at": "2024-02-08T15:30:00.000000Z",
                    "customer_id": 1,
                    "reward_id": 5
                }
            ]
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/v1/transactions?page=1",
        "last": "{{$baseUrl}}/api/v1/transactions?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/api/v1/transactions?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/api/v1/transactions?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "{{$baseUrl}}/api/v1/transactions?page=2",
                "label": "2",
                "active": false
            }
        ],
        "path": "{{$baseUrl}}/api/v1/transactions",
        "per_page": 15,
        "to": 15,
        "total": 68
    }
}
{
    "data": [],
    "links": {
        "first": "{{$baseUrl}}/api/v1/transactions?page=1",
        "last": "{{$baseUrl}}/api/v1/transactions?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": null,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/api/v1/transactions?page=1",
                "label": "1",
                "active": true
            }
        ],
        "path": "{{$baseUrl}}/api/v1/transactions",
        "per_page": 15,
        "to": null,
        "total": 0
    }
}

Create Transaction

POST
https://explore.pixalink.io.test
/api/transactions
requires authentication

Creates a new transaction record for tracking customer points/rewards. If no existing customer is found, a new customer will be automatically created with the provided phone number. Key features:

  • Points are multiplied by the customer's tier multiplier if applicable
  • Points may expire based on organisation settings
  • Handles referral tracking and rewards
  • Sends notifications if enabled in organisation settings
  • Can mark linked customer rewards as used during transaction

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/transactions" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_id\": 1,
    \"phone_number\": \"+60123456789\",
    \"amount\": 1000,
    \"space_id\": 1,
    \"remarks\": \"Purchase at Store #123\",
    \"custom_properties\": [],
    \"customer_reward_ids\": [
        1,
        2,
        3
    ]
}"
Example response:
{
    "data": {
        "id": 1,
        "amount": 1000,
        "valid_amount": 1000,
        "operation": "+",
        "type": "Purchase",
        "remarks": "Purchase at Store #123",
        "customer_id": 1,
        "space_id": 1,
        "expired_at": "2024-02-10T23:59:59.000000Z",
        "created_at": "2024-02-09T10:00:00.000000Z",
        "updated_at": "2024-02-09T10:00:00.000000Z",
        "customer_rewards": [
            {
                "id": 1,
                "customer_id": 1,
                "reward_id": 5,
                "status": "Used",
                "code": "REWARD123",
                "expired_at": "2024-12-31T23:59:59.000000Z",
                "used_at": "2024-02-09T10:00:00.000000Z"
            },
            {
                "id": 2,
                "customer_id": 1,
                "reward_id": 6,
                "status": "Used",
                "code": "REWARD456",
                "expired_at": "2024-12-31T23:59:59.000000Z",
                "used_at": "2024-02-09T10:00:00.000000Z"
            }
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "customer_id": [
            "The customer id field is required when phone number is not present."
        ],
        "phone_number": [
            "The phone number field is required when customer id is not present."
        ]
    }
}
{
    "message": "The given data was invalid.",
    "errors": {
        "customer_reward_ids.0": [
            "One or more of the selected customer rewards are invalid, used, or expired."
        ]
    }
}

Get Transaction Details

GET
https://explore.pixalink.io.test
/api/transactions/{id}
requires authentication

Retrieve detailed information about a specific transaction.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the transaction.

Example:
1
transaction
integer
required

The ID of the transaction.

Example:
1

Query Parameters

include
string

Relationships to include (customer, reward, space, customerRewards).

Example:
customer,reward,customerRewards

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/transactions/1?include=customer%2Creward%2CcustomerRewards" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "amount": 1000,
        "valid_amount": 1000,
        "operation": "+",
        "type": "Purchase",
        "remarks": "Purchase at Store #123",
        "customer_id": 1,
        "space_id": 1,
        "reward_id": null,
        "expired_at": "2024-12-31T23:59:59.000000Z",
        "created_at": "2024-02-09T10:00:00.000000Z",
        "updated_at": "2024-02-09T10:00:00.000000Z"
    }
}
{
    "message": "Record not found."
}

Users

List Users

GET
https://explore.pixalink.io.test
/api/users
requires authentication

Returns a paginated list of users belonging to the authenticated user's organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter by user name (partial match).

Example:
Alice
filter[email]
string

Filter by email (partial match).

Example:
alice@example.com
sort
string

Sort field. Allowed: id, name, created_at.

Example:
-id
per_page
integer

Records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/users?filter%5Bname%5D=Alice&filter%5Bemail%5D=alice%40example.com&sort=-id&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Alice Tan",
            "email": "alice@acme.com",
            "organisation_id": 1,
            "roles": [
                "Super Admin"
            ],
            "last_login_at": "2024-06-01T08:00:00.000000Z",
            "created_at": "2024-01-01T00:00:00.000000Z",
            "updated_at": "2024-01-01T00:00:00.000000Z"
        }
    ],
    "links": {
        "first": "...",
        "last": "...",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Show User

GET
https://explore.pixalink.io.test
/api/users/{id}
requires authentication

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The user ID.

Example:
1

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/users/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Alice",
        "email": "alice@example.com"
    }
}
{
    "message": "This action is unauthorized."
}

Calendars

List Calendars

GET
https://explore.pixalink.io.test
/api/calendars
requires authentication

Returns a paginated list of calendars belonging to the authenticated user's organisation spaces.
Supports filtering, sorting and relationship inclusion through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • space
  • reservations
Example:
space,reservations
filter[space_id]
integer

Filter by space ID.

Example:
1
filter[is_active]
boolean

Filter by active status.

Example:
true
filter[visibility]
string

Filter by visibility. Must be one of: Public, Private.

Example:
Public
filter[name]
string

Filter by calendar name (partial match).

Example:
Meeting Room
sort
string

Sort field and direction. Note: Prefix with - for descending order. Available sort fields:

  • name
  • created_at
  • updated_at
Example:
-created_at
per_page
integer

Number of records per page. Defaults to 15.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/calendars?include=space%2Creservations&filter%5Bspace_id%5D=1&filter%5Bis_active%5D=1&filter%5Bvisibility%5D=Public&filter%5Bname%5D=Meeting+Room&sort=-created_at&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Meeting Room A",
            "slug": "meeting-room-a",
            "description": "Large meeting room for up to 20 people",
            "is_active": true,
            "space_id": 1,
            "visibility": "Public",
            "min_capacity": 1,
            "max_capacity": 20,
            "is_required_approval": false,
            "is_auto_approval": true,
            "cancel_before_minutes": 60,
            "book_before_minutes": 30,
            "reminder_minutes": 15,
            "crm_auto_import": true,
            "is_unavailable_timeslots_visible": false,
            "is_qr_code_visible": true,
            "default_timeslots": [
                {
                    "start_time": "09:00",
                    "end_time": "10:00",
                    "days": [
                        "monday",
                        "tuesday",
                        "wednesday",
                        "thursday",
                        "friday"
                    ]
                }
            ],
            "block_dates": [],
            "notification_settings": {
                "new_reservation": {
                    "enabled": true,
                    "message": "Your reservation has been confirmed"
                }
            },
            "custom_properties": {},
            "channels": [
                "WhatsApp",
                "Sms"
            ],
            "terms": "Please arrive 5 minutes before your scheduled time",
            "created_at": "2025-01-31T21:16:49.000000Z",
            "updated_at": "2025-01-31T21:16:49.000000Z"
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/calendars?page=1",
        "last": "{{$baseUrl}}/api/calendars?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "path": "{{$baseUrl}}/api/calendars",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

Create Calendar

POST
https://explore.pixalink.io.test
/api/calendars
requires authentication

Creates a new calendar in the system.
The calendar will be associated with the specified space in the authenticated user's organisation.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/calendars" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Meeting Room A\",
    \"slug\": \"meeting-room-a\",
    \"description\": \"Large meeting room for up to 20 people\",
    \"space_id\": 1,
    \"is_active\": true,
    \"visibility\": \"Public\",
    \"min_capacity\": 1,
    \"max_capacity\": 20,
    \"is_required_approval\": false,
    \"is_auto_approval\": true,
    \"cancel_before_minutes\": 60,
    \"book_before_minutes\": 30,
    \"is_max_advance_booking_enabled\": false,
    \"max_advance_booking_days\": 30,
    \"reminder_minutes\": 15,
    \"crm_auto_import\": true,
    \"is_unavailable_timeslots_visible\": false,
    \"is_qr_code_visible\": true,
    \"default_timeslots\": [
        \"eos\"
    ],
    \"block_dates\": [
        \"autem\"
    ],
    \"notification_settings\": {
        \"new_reservation\": {
            \"enabled\": true,
            \"message\": \"Your reservation has been confirmed\"
        }
    },
    \"custom_properties\": [],
    \"channels\": [
        \"WhatsApp\",
        \"Sms\"
    ],
    \"terms\": \"Please arrive 5 minutes before your scheduled time\"
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "Meeting Room A",
        "slug": "meeting-room-a",
        "description": "Large meeting room for up to 20 people",
        "is_active": true,
        "space_id": 1,
        "visibility": "Public",
        "min_capacity": 1,
        "max_capacity": 20,
        "is_required_approval": false,
        "is_auto_approval": true,
        "cancel_before_minutes": 60,
        "book_before_minutes": 30,
        "reminder_minutes": 15,
        "crm_auto_import": true,
        "is_unavailable_timeslots_visible": false,
        "is_qr_code_visible": true,
        "default_timeslots": [
            {
                "start_time": "09:00",
                "end_time": "10:00",
                "days": [
                    "monday",
                    "tuesday",
                    "wednesday",
                    "thursday",
                    "friday"
                ]
            }
        ],
        "block_dates": [],
        "notification_settings": {
            "new_reservation": {
                "enabled": true,
                "message": "Your reservation has been confirmed"
            }
        },
        "custom_properties": {},
        "channels": [
            "WhatsApp",
            "Sms"
        ],
        "terms": "Please arrive 5 minutes before your scheduled time",
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    },
    "message": "Calendar created successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name field is required."
        ],
        "space_id": [
            "The selected space id is invalid."
        ],
        "max_capacity": [
            "The max capacity must be greater than min capacity."
        ]
    }
}

Show Calendar Details

GET
https://explore.pixalink.io.test
/api/calendars/{id}
requires authentication

Retrieves detailed information about a specific calendar, including any requested relationships.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the calendar.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • space
  • reservations
Example:
space,reservations

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/calendars/1?include=space%2Creservations" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "name": "Meeting Room A",
        "slug": "meeting-room-a",
        "description": "Large meeting room for up to 20 people",
        "is_active": true,
        "space_id": 1,
        "visibility": "Public",
        "min_capacity": 1,
        "max_capacity": 20,
        "is_required_approval": false,
        "is_auto_approval": true,
        "cancel_before_minutes": 60,
        "book_before_minutes": 30,
        "reminder_minutes": 15,
        "crm_auto_import": true,
        "is_unavailable_timeslots_visible": false,
        "is_qr_code_visible": true,
        "default_timeslots": [
            {
                "start_time": "09:00",
                "end_time": "10:00",
                "days": [
                    "monday",
                    "tuesday",
                    "wednesday",
                    "thursday",
                    "friday"
                ]
            }
        ],
        "block_dates": [],
        "notification_settings": {
            "new_reservation": {
                "enabled": true,
                "message": "Your reservation has been confirmed"
            }
        },
        "custom_properties": {},
        "channels": [
            "WhatsApp",
            "Sms"
        ],
        "terms": "Please arrive 5 minutes before your scheduled time",
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    }
}
{
    "message": "Record not found"
}

Update Calendar

PUT
PATCH
https://explore.pixalink.io.test
/api/calendars/{id}
requires authentication

Updates an existing calendar's information.
All fields are optional.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the calendar.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/calendars/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Meeting Room A\",
    \"slug\": \"meeting-room-a\",
    \"description\": \"Large meeting room for up to 20 people\",
    \"space_id\": 1,
    \"is_active\": true,
    \"visibility\": \"Public\",
    \"min_capacity\": 1,
    \"max_capacity\": 20,
    \"is_required_approval\": false,
    \"is_auto_approval\": true,
    \"cancel_before_minutes\": 60,
    \"book_before_minutes\": 30,
    \"is_max_advance_booking_enabled\": false,
    \"max_advance_booking_days\": 30,
    \"reminder_minutes\": 15,
    \"crm_auto_import\": true,
    \"is_unavailable_timeslots_visible\": false,
    \"is_qr_code_visible\": true,
    \"default_timeslots\": [
        \"et\"
    ],
    \"block_dates\": [
        \"deleniti\"
    ],
    \"notification_settings\": {
        \"new_reservation\": {
            \"enabled\": true,
            \"message\": \"Your reservation has been confirmed.\"
        }
    },
    \"custom_properties\": [],
    \"channels\": [
        \"WhatsApp\",
        \"Sms\"
    ],
    \"terms\": \"Please arrive 5 minutes before your scheduled time\"
}"
Example response:
{
    "data": {
        "id": 1,
        "name": "Meeting Room A",
        "slug": "meeting-room-a",
        "description": "Large meeting room for up to 20 people",
        "is_active": true,
        "space_id": 1,
        "visibility": "Public",
        "min_capacity": 1,
        "max_capacity": 20,
        "is_required_approval": false,
        "is_auto_approval": true,
        "cancel_before_minutes": 60,
        "book_before_minutes": 30,
        "reminder_minutes": 15,
        "crm_auto_import": true,
        "is_unavailable_timeslots_visible": false,
        "is_qr_code_visible": true,
        "default_timeslots": [
            {
                "start_time": "09:00",
                "end_time": "10:00",
                "days": [
                    "monday",
                    "tuesday",
                    "wednesday",
                    "thursday",
                    "friday"
                ]
            }
        ],
        "block_dates": [],
        "notification_settings": {
            "new_reservation": {
                "enabled": true,
                "message": "Your reservation has been confirmed"
            }
        },
        "custom_properties": {},
        "channels": [
            "WhatsApp",
            "Sms"
        ],
        "terms": "Please arrive 5 minutes before your scheduled time",
        "created_at": "2025-01-31T21:16:49.000000Z",
        "updated_at": "2025-01-31T21:16:49.000000Z"
    },
    "message": "Calendar updated successfully"
}
{
    "message": "Record not found"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "name": [
            "The name field is required."
        ],
        "space_id": [
            "The selected space id is invalid."
        ],
        "max_capacity": [
            "The max capacity must be greater than min capacity."
        ]
    }
}

Delete Calendar

DELETE
https://explore.pixalink.io.test
/api/calendars/{id}
requires authentication

Deletes a calendar from the system.
Only calendars without active reservations can be deleted.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the calendar.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/calendars/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
[Empty response]
{
    "message": "Record not found"
}
{
    "message": "Cannot delete calendar with active reservations"
}

Reservations

List Reservations

GET
https://explore.pixalink.io.test
/api/reservations
requires authentication

Returns a paginated list of reservations belonging to the authenticated user's organisation.
Results can be filtered, sorted and include related data through query parameters.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

include
string

Comma-separated list of relationships to include:

  • calendar
  • customer
  • calendar.space
Example:
calendar,customer
filter[calendar_id]
integer

Filter by calendar ID.

Example:
1
filter[customer_id]
integer

Filter by customer ID.

Example:
1
filter[status]
string

Filter by reservation status. Must be one of:

  • pending
  • rejected
  • reserved
  • cancelled
  • no_show
Example:
reserved
filter[date]
string

Filter by reservation date. Use ISO 8601 format (YYYY-MM-DD).

Example:
2024-01-01
filter[date_from]
string

Filter reservations from this date onwards (inclusive). Use ISO 8601 format (YYYY-MM-DD).

Example:
2024-01-01
filter[date_to]
string

Filter reservations up to this date (inclusive). Use ISO 8601 format (YYYY-MM-DD).

Example:
2024-01-31
filter[name]
string

Filter by customer name (partial match).

Example:
John
filter[email]
string

Filter by customer email (partial match).

Example:
john@example.com
filter[phone_number]
string

Filter by customer phone number (partial match).

Example:
+60123
sort
string

Sort field and direction. Allowed fields: date, start_at, created_at, status, name.

Example:
-date
per_page
integer

Number of records per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/reservations?include=calendar%2Ccustomer&filter%5Bcalendar_id%5D=1&filter%5Bcustomer_id%5D=1&filter%5Bstatus%5D=reserved&filter%5Bdate%5D=2024-01-01&filter%5Bdate_from%5D=2024-01-01&filter%5Bdate_to%5D=2024-01-31&filter%5Bname%5D=John&filter%5Bemail%5D=john%40example.com&filter%5Bphone_number%5D=%2B60123&sort=-date&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "ref_id": "RSV001234",
            "date": "2024-03-15",
            "start_at": "2024-03-15T14:30:00.000000Z",
            "end_at": "2024-03-15T16:00:00.000000Z",
            "name": "John Smith",
            "email": "john.smith@example.com",
            "phone_number": "+60123456789",
            "number_of_guests": 4,
            "status": "reserved",
            "remarks": "Birthday celebration",
            "custom_fields": {
                "dietary_requirements": "Vegetarian",
                "special_requests": "Window seat preferred"
            },
            "timeslot_id": 5,
            "calendar_id": 1,
            "customer_id": 123,
            "reminder_sent_at": "2024-03-14T14:30:00.000000Z",
            "rejection_reason": null,
            "created_at": "2024-03-01T10:15:30.000000Z",
            "updated_at": "2024-03-10T16:22:45.000000Z",
            "calendar": {
                "id": 1,
                "name": "Restaurant Reservations",
                "slug": "restaurant-reservations",
                "description": "Main dining room reservations",
                "is_active": true,
                "space_id": 1,
                "visibility": "public",
                "min_capacity": 1,
                "max_capacity": 8,
                "is_required_approval": true,
                "is_auto_approval": false,
                "cancel_before_minutes": 60,
                "book_before_minutes": 30,
                "reminder_minutes": 1440,
                "crm_auto_import": true,
                "is_unavailable_timeslots_visible": false,
                "is_qr_code_visible": true,
                "space": {
                    "id": 1,
                    "name": "Main Branch",
                    "slug": "main-branch",
                    "description": "Our flagship restaurant location"
                }
            },
            "customer": {
                "id": 123,
                "name": "John Smith",
                "email": "john.smith@example.com",
                "phone_number": "+60123456789",
                "current_point": 2500,
                "tier_id": 2
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/reservations?page=1",
        "last": "{{$baseUrl}}/reservations?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/reservations?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/reservations?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": "{{$baseUrl}}/reservations?page=2",
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "{{$baseUrl}}/reservations",
        "per_page": 15,
        "to": 15,
        "total": 68
    }
}

Create Reservation

POST
https://explore.pixalink.io.test
/api/reservations
requires authentication

Creates a new reservation in the system.
The reservation will be associated with a calendar and optionally with a customer.
Auto-generates a unique reference ID.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/reservations" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"date\": \"2024-03-15\",
    \"start_at\": \"2024-03-15T14:30:00Z\",
    \"end_at\": \"2024-03-15T16:00:00Z\",
    \"name\": \"John Smith\",
    \"email\": \"john.smith@example.com\",
    \"phone_number\": \"+60123456789\",
    \"number_of_guests\": 4,
    \"status\": \"pending\",
    \"remarks\": \"Birthday celebration, window seat preferred\",
    \"custom_fields\": {
        \"dietary_requirements\": \"Vegetarian\",
        \"special_requests\": \"Birthday cake arrangement\"
    },
    \"timeslot_id\": 5,
    \"calendar_id\": 1,
    \"customer_id\": 123,
    \"rejection_reason\": \"Fully booked on requested date\"
}"
Example response:
{
    "data": {
        "id": 1,
        "ref_id": "RSV001234",
        "date": "2024-03-15",
        "start_at": "2024-03-15T14:30:00.000000Z",
        "end_at": "2024-03-15T16:00:00.000000Z",
        "name": "John Smith",
        "email": "john.smith@example.com",
        "phone_number": "+60123456789",
        "number_of_guests": 4,
        "status": "pending",
        "remarks": "Birthday celebration",
        "custom_fields": {
            "dietary_requirements": "Vegetarian"
        },
        "timeslot_id": null,
        "calendar_id": 1,
        "customer_id": null,
        "reminder_sent_at": null,
        "rejection_reason": null,
        "created_at": "2024-03-01T10:15:30.000000Z",
        "updated_at": "2024-03-01T10:15:30.000000Z"
    },
    "message": "Reservation created successfully"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "date": [
            "The date must be a valid date after today."
        ],
        "start_at": [
            "The start at field is required."
        ],
        "calendar_id": [
            "The selected calendar id is invalid."
        ],
        "number_of_guests": [
            "The number of guests must be at least 1."
        ]
    }
}

Show Reservation Details

GET
https://explore.pixalink.io.test
/api/reservations/{id}
requires authentication

Retrieves detailed information about a specific reservation, including any requested relationships.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reservation to show.

Example:
1

Query Parameters

include
string

Comma-separated list of relationships to include. Available relationships:

  • calendar
  • customer
  • calendar.space
Example:
calendar,customer

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/reservations/1?include=calendar%2Ccustomer" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": {
        "id": 1,
        "ref_id": "RSV001234",
        "date": "2024-03-15",
        "start_at": "2024-03-15T14:30:00.000000Z",
        "end_at": "2024-03-15T16:00:00.000000Z",
        "name": "John Smith",
        "email": "john.smith@example.com",
        "phone_number": "+60123456789",
        "number_of_guests": 4,
        "status": "reserved",
        "remarks": "Birthday celebration",
        "custom_fields": {
            "dietary_requirements": "Vegetarian"
        },
        "timeslot_id": 5,
        "calendar_id": 1,
        "customer_id": 123,
        "reminder_sent_at": "2024-03-14T14:30:00.000000Z",
        "rejection_reason": null,
        "created_at": "2024-03-01T10:15:30.000000Z",
        "updated_at": "2024-03-10T16:22:45.000000Z",
        "calendar": {
            "id": 1,
            "name": "Restaurant Reservations",
            "space_id": 1
        }
    }
}
{
    "message": "Record not found"
}

Update Reservation

PUT
PATCH
https://explore.pixalink.io.test
/api/reservations/{id}
requires authentication

Updates an existing reservation's information.
All fields are optional.
Status transitions are validated according to business rules.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reservation to update.

Example:
1

Body Parameters

Response Fields

Example request:
curl --request PUT \
    "https://explore.pixalink.io.test/api/reservations/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"date\": \"2024-03-15\",
    \"start_at\": \"2024-03-15T14:30:00Z\",
    \"end_at\": \"2024-03-15T16:00:00Z\",
    \"name\": \"John Smith\",
    \"email\": \"john.smith@example.com\",
    \"phone_number\": \"+60123456789\",
    \"number_of_guests\": 4,
    \"status\": \"pending\",
    \"remarks\": \"Birthday celebration, window seat preferred\",
    \"custom_fields\": {
        \"dietary_requirements\": \"Vegetarian\",
        \"special_requests\": \"Birthday cake arrangement\"
    },
    \"timeslot_id\": 5,
    \"calendar_id\": 1,
    \"customer_id\": 123,
    \"rejection_reason\": \"Fully booked on requested date\"
}"
Example response:
{
    "data": {
        "id": 1,
        "ref_id": "RSV001234",
        "date": "2024-03-15",
        "start_at": "2024-03-15T14:30:00.000000Z",
        "end_at": "2024-03-15T16:00:00.000000Z",
        "name": "John Smith",
        "email": "john.smith@example.com",
        "phone_number": "+60123456789",
        "number_of_guests": 6,
        "status": "reserved",
        "remarks": "Anniversary celebration - updated guest count",
        "custom_fields": {
            "dietary_requirements": "Vegetarian, Gluten-free"
        },
        "timeslot_id": 5,
        "calendar_id": 1,
        "customer_id": 123,
        "reminder_sent_at": "2024-03-14T14:30:00.000000Z",
        "rejection_reason": null,
        "created_at": "2024-03-01T10:15:30.000000Z",
        "updated_at": "2024-03-10T16:22:45.000000Z"
    },
    "message": "Reservation updated successfully"
}
{
    "message": "Reservation not found"
}
{
    "message": "The given data was invalid.",
    "errors": {
        "status": [
            "Invalid status transition from reserved to pending."
        ],
        "number_of_guests": [
            "The number of guests must be at least 1."
        ]
    }
}

Delete Reservation

DELETE
https://explore.pixalink.io.test
/api/reservations/{id}
requires authentication

Soft deletes a reservation from the system.
The reservation can be restored later if needed.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

URL Parameters

id
integer
required

The ID of the reservation to delete.

Example:
1
Example request:
curl --request DELETE \
    "https://explore.pixalink.io.test/api/reservations/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "message": "Reservation deleted successfully"
}
{
    "message": "Record not found"
}

Endpoints

Get authenticated user

GET
https://explore.pixalink.io.test
/api/user
requires authentication

Retrieves the currently authenticated user's information.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/user" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "id": 3,
    "organisation_id": 2,
    "name": "User",
    "email": "vendor@pixalink.io",
    "email_verified_at": "2025-01-31T21:16:49.000000Z",
    "created_at": "2025-01-31T21:16:49.000000Z",
    "updated_at": "2025-01-31T21:16:49.000000Z",
    "deleted_at": null
}

Location Management

List all countries

GET
https://explore.pixalink.io.test
/api/countries
requires authentication

Get a list of all countries with their details.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter countries by name.

Example:
Malaysia
filter[nationality]
string

Filter countries by nationality.

Example:
Malaysian
filter[iso]
string

Filter countries by ISO code.

Example:
MY
per_page
integer

Number of records to display per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/countries?filter%5Bname%5D=Malaysia&filter%5Bnationality%5D=Malaysian&filter%5Biso%5D=MY&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Malaysia",
            "nationality": "Malaysian",
            "iso": "MY",
            "iso3": "MYS"
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/countries?page=1",
        "last": "{{$baseUrl}}/api/countries?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/api/countries?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "{{$baseUrl}}/api/countries",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

List all states

GET
https://explore.pixalink.io.test
/api/states
requires authentication

Get a list of all states with their associated countries.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter states by name.

Example:
Selangor
filter[country_id]
integer

Filter states by country ID.

Example:
1
include
string

Include related models (Possible values: country).

Example:
country
per_page
integer

Number of records to display per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/states?filter%5Bname%5D=Selangor&filter%5Bcountry_id%5D=1&include=country&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Selangor",
            "country": {
                "id": 1,
                "name": "Malaysia",
                "nationality": "Malaysian",
                "iso": "MY",
                "iso3": "MYS",
                "phone_code": "60"
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/states?page=1",
        "last": "{{$baseUrl}}/api/states?page=5",
        "prev": null,
        "next": "{{$baseUrl}}/api/states?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 5,
        "path": "{{$baseUrl}}/api/states",
        "per_page": 15,
        "to": 15,
        "total": 75
    }
}

List all cities

GET
https://explore.pixalink.io.test
/api/cities
requires authentication

Get a list of all cities with their associated states.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Query Parameters

filter[name]
string

Filter cities by name.

Example:
Petaling Jaya
filter[state_id]
integer

Filter cities by state ID.

Example:
1
include
string

Include related models (Possible values: state, state.country).

Example:
state,state.country
sort
string

Sort by specified field. Prefix with - for descending sort. Possible values: name

Example:
-name
per_page
integer

Number of records to display per page.

Example:
15

Response Fields

Example request:
curl --request GET \
    --get "https://explore.pixalink.io.test/api/cities?filter%5Bname%5D=Petaling+Jaya&filter%5Bstate_id%5D=1&include=state%2Cstate.country&sort=-name&per_page=15" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
Example response:
{
    "data": [
        {
            "id": 1,
            "name": "Petaling Jaya",
            "state": {
                "id": 1,
                "name": "Selangor",
                "country": {
                    "id": 1,
                    "name": "Malaysia",
                    "nationality": "Malaysian",
                    "iso": "MY",
                    "iso3": "MYS",
                    "phone_code": "60"
                }
            }
        }
    ],
    "links": {
        "first": "{{$baseUrl}}/api/cities?page=1",
        "last": "{{$baseUrl}}/api/cities?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "active": false
            },
            {
                "url": "{{$baseUrl}}/api/cities?page=1",
                "label": "1",
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "active": false
            }
        ],
        "path": "{{$baseUrl}}/api/cities",
        "per_page": 15,
        "to": 1,
        "total": 1
    }
}

SSO

Generate a signed SSO login URL for a customer.

POST
https://explore.pixalink.io.test
/api/sso/redirect
requires authentication

Verifies the HMAC-signed request, finds or creates the customer by phone number, then returns a temporary signed URL that logs the customer into the loyalty portal. The signed URL is valid for 10 minutes.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/sso/redirect" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"customer_phone\": \"+60123456789\",
    \"space_id\": 42,
    \"timestamp\": 1746518400,
    \"redirect_to\": \"rewards\"
}"
Example response:
{
    "redirect_url": "https://explore.pixalink.io/space/1/loyalty/login/42?expires=1746518400&signature=abc123..."
}
{
    "message": "Invalid signature."
}
{
    "message": "Client is not configured for SSO."
}
{
    "message": "Not Found"
}
{
    "message": "The customer phone field is required.",
    "errors": {
        "customer_phone": [
            "The customer phone field is required."
        ]
    }
}

Resolve an outbound SSO ticket.

POST
https://explore.pixalink.io.test
/api/sso/resolve
requires authentication

Verifies the HMAC-signed request, then exchanges a single-use ticket for the customer identity it was minted against. The ticket is consumed on first use, so a second call with the same ticket returns 410. Only the organisation that owns the ticket may resolve it.

Headers

Authorization
Example:
Bearer {YOUR_AUTH_KEY}
Content-Type
Example:
application/json
Accept
Example:
application/json

Body Parameters

Response Fields

Example request:
curl --request POST \
    "https://explore.pixalink.io.test/api/sso/resolve" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"ticket\": \"kP3x…opaque…9Qz\",
    \"timestamp\": 1746518400
}"
Example response:
{
    "customer": {
        "id": 42,
        "name": "Jane Doe",
        "phone_number": "+60123456789",
        "email": "jane@example.com",
        "space_id": 1,
        "organisation_id": 7
    },
    "context": {}
}
{
    "message": "Invalid signature."
}
{
    "message": "Ticket not found, already used, or expired."
}