A complete guide for external developers who want to connect to the LoyalAxis CRM REST API: authentication, request format, and working examples for every common operation.
What is the LoyalAxis CRM API?
The LoyalAxis CRM API is a REST API built on top of the WordPress REST API. It lets an external application — a website, a mobile app, another CRM, or an automation script — talk directly to your LoyalAxis CRM installation over HTTPS.
Typical use cases:
- Create or update **Leads** from an external website form, landing page, or ad platform.
- Read or update a customer's **Sales Opportunity** cards from another system.
- Look up or create **CRM users** from a mobile app or a third-party portal.
- Pull dashboard, kanban, or reporting data into an external BI tool.
- Automate workflows that used to require manual work inside the CRM panel.
Every request is authenticated, JSON-based, and returns predictable HTTP status codes, so it can be consumed by any language or platform that can make an HTTPS request.
Enabling the API
> **Before you begin:** The REST API is **disabled by default**. It must be turned on by an administrator before any endpoint (other than discovery) will respond. Add the following to your site's `wp-config.php` file:
php
define( 'LA24_API_ENABLED', true );
define( 'hash_key_jwt_token', 'YOUR_CUSTOM_SECRET_KEY' );
define( 'jwt_auth_expire', 604800 ); // token lifetime in seconds, default is 7 days| Constant | Required | Description |
|---|---|---|
| `LA24_API_ENABLED` | Yes | Must be `true` to expose the API endpoints. |
| `hash_key_jwt_token` | Yes | Secret key used to sign and verify authentication tokens. Use a long, random string and keep it private. |
| `jwt_auth_expire` | No | Token lifetime in seconds. Defaults to 7 days (`604800`) if omitted. |

Base URL and Request Format
All endpoints are served under your site's standard WordPress REST API prefix:
javascript
https://yourdomain.com/wp-json/{namespace}/v{version}/{endpoint}- `yourdomain.com` — replace with your actual site domain.
- `{namespace}` — identifies the module (see table below).
- `v{version}` — the module's API version, e.g. `v1`.
- `{endpoint}` — the specific action, e.g. `lead`, `get-kanban`.
| Namespace | Module | Example |
|---|---|---|
| `core` | Authentication (token issue/validate) | `/wp-json/core/token` |
| `ums` | Users & Leads | `/wp-json/ums/v1/lead` |
| `sales-opportunity` | Sales Opportunity (CRM pipeline) | `/wp-json/sales-opportunity/v1/get-kanban` |
| `player` | Player accounts & licenses | `/wp-json/player/v1/getuser` |
| `knowledge` | Knowledge Base | `/wp-json/knowledge/v1/...` |
| `support` | Support tickets | `/wp-json/support/v1/...` |
| `notifications` | Notifications | `/wp-json/notifications/v1/...` |
| `warehouse` | Warehouse / inventory | `/wp-json/warehouse/v1/...` |
| `accounting` | Accounting | `/wp-json/accounting/v1/...` |
**Request format**
- Send `POST`, `PATCH`, and `DELETE` bodies as JSON with the header `Content-Type: application/json`. Form-encoded bodies are also accepted on most endpoints, but JSON is recommended.
- Send `GET` parameters as a standard URL query string.
- Every response is JSON, whatever the HTTP method or result.
Authentication
The API uses **JWT (JSON Web Token)** bearer authentication. You exchange a username and password once for a token, then send that token with every subsequent request.
Step 1 — Request a token
| Field | Location | Required | Description |
|---|---|---|---|
| `username` | Body | Yes | Username of a CRM user with API access (typically an administrator). |
| `password` | Body | Yes | Password for that user. |
javascript
POST /wp-json/core/token**Example response**
json
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user_email": "admin@yourdomain.com",
"user_nicename": "admin",
"user_display_name": "Site Admin"
}| Field | Description |
|---|---|
| `token` | The JWT to send in the `Authorization` header on every subsequent request. |
| `user_email` | Email address of the authenticated user. |
| `user_nicename` | The user's WordPress "nicename" (URL-safe username). |
| `user_display_name` | The user's display name. |
Step 2 — Send the token on every request
Add this header to every authenticated request:
javascript
Authorization: Bearer {token}Step 3 — Validate a token (optional)
javascript
POST /wp-json/core/token/validate| Header | Required | Description |
|---|---|---|
| `Authorization` | Yes | `Bearer {token}` — the token to check. |
A valid token returns:
json
{
"code": "jwt_auth_valid_token",
"data": { "status": 200 }
}Token errors
Authentication failures use this shape (note: the error code is nested differently from normal endpoint errors — see [Request & Response Format](#request-and-response-format)):
json
{
"code": "[jwt_auth] incorrect_password",
"message": "The password you entered is incorrect.",
"data": { "status": 403 }
}Common codes: `incorrect_password`, `invalid_username` (bad login), `jwt_auth_no_auth_header` (missing `Authorization` header), `jwt_auth_bad_auth_header` (header isn't `Bearer `), `jwt_auth_invalid_token` (expired or tampered token), `jwt_auth_bad_iss` (token was issued by a different site).
Your First API Request
This walkthrough gets a real response back from the API in two calls: get a token, then fetch a lead.
Step 1 — Get a token
**cURL**
bash
curl -X POST https://yourdomain.com/wp-json/core/token \
-d "username=your_admin_username" \
-d "password=your_admin_password"**JavaScript (fetch)**
javascript
const response = await fetch('https://yourdomain.com/wp-json/core/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
username: 'your_admin_username',
password: 'your_admin_password',
}),
});
const { token } = await response.json();
console.log(token);**PHP**
php
$response = wp_remote_post( 'https://yourdomain.com/wp-json/core/token', array(
'body' => array(
'username' => 'your_admin_username',
'password' => 'your_admin_password',
),
) );
$body = json_decode( wp_remote_retrieve_body( $response ), true );
$token = $body['token'] ?? null;Step 2 — Call an endpoint with the token
Example: retrieve a lead by ID (`GET /ums/v1/lead/:id`).
**cURL**
bash
curl -X GET https://yourdomain.com/wp-json/ums/v1/lead/123 \
-H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."**JavaScript (fetch)**
javascript
const response = await fetch('https://yourdomain.com/wp-json/ums/v1/lead/123', {
method: 'GET',
headers: { 'Authorization': `Bearer ${token}` },
});
const result = await response.json();
console.log(result);**PHP**
php
$response = wp_remote_get( 'https://yourdomain.com/wp-json/ums/v1/lead/123', array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
),
) );
$result = json_decode( wp_remote_retrieve_body( $response ), true );Example response
json
{
"status": 200,
"message": "Lead retrieved successfully.",
"data": {
"id": 123,
"display_name": "John Doe",
"email": "john@example.com",
"registered_date": "2026-05-01 10:12:00",
"customer_type": "1",
"first_name": "John",
"last_name": "Doe",
"phone": "+989123456789",
"phone_numbers": [
{ "tell": "+989123456789", "desc": "", "default": "1" }
],
"gender": "1",
"job": "Manager",
"created_by": { "id": 1, "name": "Site Admin" }
}
}Field-by-field explanation
| Field | Type | Description |
|---|---|---|
| `status` | Number | HTTP-style status code repeated in the body (`200` = success). |
| `message` | String | Human-readable summary of the result. |
| `data.id` | Number | The lead's unique ID. |
| `data.display_name` | String | Full display name shown in the CRM. |
| `data.email` | String | Lead's email address. |
| `data.registered_date` | String | When the lead was created (`Y-m-d H:i:s`). |
| `data.customer_type` | String | `1` = individual, `2` = company. |
| `data.first_name` / `data.last_name` | String | Name fields (individual). |
| `data.company_name` | String | Present only when `customer_type` is `2`. |
| `data.phone` | String | Primary phone number. |
| `data.phone_numbers` | Array | All phone numbers on file, each with `tell`, `desc`, and `default`. |
| `data.gender` | String | `1` = male, `2` = female. |
| `data.job` | String | Job title, if provided. |
| `data.created_by` | Object | The CRM user (`id`, `name`) who created the lead. |

API Reference Overview
Discovering endpoints
Every endpoint in the CRM is grouped by module (`Authentication`, `Leads`, `SalesOpportunity`, `Player`, `Knowledge Base`, `Support`, `Notifications`, `Warehouse`, `Accounting`, and more). The complete, always up-to-date list of endpoints — with every parameter and example — is published at the link in [Official API Reference](#official-api-reference). This guide covers the concepts and the most common operations; use the reference for the full endpoint catalog.
Request and response format
Almost every module endpoint returns the same envelope:
json
{
"status": 200,
"message": "Optional human-readable message.",
"data": {}
}| Field | Always present | Description |
|---|---|---|
| `status` | Yes | Numeric status code, mirrors the HTTP status. |
| `message` | Usually | Short description of the result, useful for logging or display. |
| `data` | On success | The actual payload — an object, array, or list of records. |
The **authentication endpoints** (`/core/token`, `/core/token/validate`) are the one exception: on failure they return a WordPress-style error object instead:
json
{
"code": "jwt_auth_invalid_token",
"message": "Signature verification failed.",
"data": { "status": 403 }
}Always check the **HTTP status code** of the response first — it is authoritative — and use `status`/`code` and `message` in the body to display or log details.
HTTP status codes
| Code | Meaning |
|---|---|
| `200` | Success. |
| `400` | Bad request — a required parameter is missing or invalid. |
| `403` | Forbidden — missing/invalid token, or the authenticated user lacks permission for this action. |
| `404` | Not found — the record (lead, card, board, etc.) does not exist. |
| `500` | Server error — something failed while processing the request; check `message` for detail. |
Pagination
List endpoints that can return many records accept `page` and `per_page` query parameters and return a `pagination` object:
javascript
GET /wp-json/sales-opportunity/v1/get-cards?page=2&per_page=25json
{
"status": 200,
"data": [ /* records for this page */ ],
"pagination": {
"page": 2,
"per_page": 25,
"total": 118,
"total_pages": 5
}
}| Field | Description |
|---|---|
| `page` | The page you requested (default `1`). |
| `per_page` | Records per page (default varies by endpoint, commonly `25`). |
| `total` | Total number of matching records across all pages. |
| `total_pages` | Total number of pages available. |
Filtering and search
Most list endpoints accept a `s` query parameter for a free-text search (name, email, title, depending on the endpoint), plus endpoint-specific filters such as `date_from` / `date_to`, `user_id`, `tag`, or `type`. Some list endpoints also accept a `sort` parameter for ordering results (the accepted values are documented per endpoint in the full reference). Filters that aren't supported by a given endpoint are simply ignored — check the endpoint's own documentation for the exact list it accepts.
Handling errors
- Check the HTTP status code.
- If it's not `2xx`, read `message` (or `code` for auth endpoints) for the reason.
- For `403` on a non-auth endpoint, re-authenticate — the token may have expired — before assuming a permissions problem.
- For `400`, fix the request body/parameters listed in `message` and retry.
Examples
All examples assume you already have a valid token stored in a `token` variable, sent as `Authorization: Bearer {token}`.
Retrieving data
bash
curl -X GET "https://yourdomain.com/wp-json/ums/v1/lead/123" \
-H "Authorization: Bearer your_token_here"Searching records
bash
curl -X GET "https://yourdomain.com/wp-json/sales-opportunity/v1/search-leads?s=john&limit=10" \
-H "Authorization: Bearer your_token_here"json
{
"status": 200,
"data": [
{
"id": 123,
"label": "John Doe",
"name": "John Doe",
"email": "john@example.com",
"profile_url": "https://yourdomain.com/panel/profile/?id=123&clue=on",
"type": "clue"
}
]
}Creating a record
bash
curl -X POST "https://yourdomain.com/wp-json/ums/v1/lead" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{
"first_name": "John",
"last_name": "Doe",
"lead_email": "john@example.com",
"phone": "+989123456789",
"customer_type": "1"
}'json
{
"status": 200,
"message": "Lead created successfully.",
"data": {
"status": true,
"profile_id": 124,
"profile_link": "https://yourdomain.com/panel/profile/?id=124",
"display_name": "John Doe"
}
}Updating a record
`PATCH` updates only the fields you send; every other field on the record is left untouched.
bash
curl -X PATCH "https://yourdomain.com/wp-json/ums/v1/lead/124" \
-H "Authorization: Bearer your_token_here" \
-H "Content-Type: application/json" \
-d '{ "phone": "+989350000000" }'json
{
"status": 200,
"message": "Lead updated successfully.",
"data": {
"status": true,
"profile_id": 124,
"profile_link": "https://yourdomain.com/panel/profile/?id=124",
"display_name": "John Doe"
}
}Deleting a record
bash
curl -X DELETE "https://yourdomain.com/wp-json/ums/v1/lead/124" \
-H "Authorization: Bearer your_token_here"json
{
"status": 200,
"message": "Lead deleted successfully.",
"data": { "success": true, "lead_id": 124 }
}Paginated list with filters
bash
curl -X GET "https://yourdomain.com/wp-json/sales-opportunity/v1/get-cards?so_id=1&page=1&per_page=25&s=john" \
-H "Authorization: Bearer your_token_here"Handling authentication failures
**Missing token**
bash
curl -X GET "https://yourdomain.com/wp-json/ums/v1/lead/123"json
{ "status": 403, "message": "The request cannot be processed." }**Expired or invalid token**
json
{
"code": "jwt_auth_invalid_token",
"message": "Expired token",
"data": { "status": 403 }
}When you see a `403` with a `jwt_auth_*` code, request a fresh token (see [Authentication](#authentication)) and retry the call. If the `403` comes back with a plain `status`/`message` body instead, the token is valid but the user doesn't have permission for that action — check the user's role and capabilities in the CRM instead.

Official API Reference
This guide covers the concepts you need to get started. For the complete, endpoint-by-endpoint reference — every parameter, every response field, and every module — see the official LoyalAxis CRM API documentation:
**https://yourdomain.com/apidoc/**
> Replace `yourdomain.com` with your actual site domain in every example in this guide.