Data & API Integration
The shared API contract, the bundled Express mock API, the request/response shape, and how to point any edition at your own backend.
Every edition of Taxi CRM 2026 fetches its list and form data over HTTP. The endpoint
surface is defined once in the shared api-contract.mjs (exported by
@taxi-crm/design-system) and mirrored by the bundled Express mock API in services/api.
You point any edition at your own backend by changing one base URL.
The shared API contract
packages/design-system/api-contract.mjs is the single source of truth for the API surface.
It is framework-agnostic (no window/DOM access) and exports three things:
import { endpoints, headers, createApi } from '@taxi-crm/design-system/api-contract';
const api = createApi(); // base '/api' (same-origin via Firebase rewrite)
const res = await api.get(endpoints.Driver.getDriver);| Export | What it is |
|---|---|
endpoints | A map of endpoint paths grouped by feature, e.g. endpoints.Driver.getDriver → '/Driver/getDriver'. |
headers | The default request headers — { x_pvr_tech_studio_access: '123' }. |
createApi(baseUrl) | A tiny fetch wrapper returning { get, post }, with headers merged in automatically. |
The base URL
createApi() defaults to a same-origin base of /api in the browser (the Firebase
Hosting rewrite forwards /api to the Cloud Run service), and to
http://localhost:8080/api when running on localhost:
export function defaultBaseUrl() {
if (typeof window !== 'undefined' && window.location?.hostname === 'localhost') {
return 'http://localhost:8080/api';
}
return '/api';
}Pass your own base to override it: createApi('https://api.yourcompany.com').
The fetch wrapper
createApi is the React/Vue replacement for the HTML edition's scattered $.ajax calls.
Every request merges in the auth header; non-2xx responses throw:
export function createApi(baseUrl = defaultBaseUrl()) {
const request = async (endpoint, options = {}) => {
const res = await fetch(baseUrl + endpoint, {
...options,
headers: { ...headers, ...(options.headers || {}) },
});
if (!res.ok) throw new Error(`API ${endpoint} -> ${res.status}`);
return res.json();
};
return {
get: (endpoint) => request(endpoint, { method: 'GET' }),
post: (endpoint, body) => request(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
}),
};
}The endpoint groups
endpoints covers 48 feature groups (≈77 endpoints). The surface is almost entirely
GET-only — these are read-only mock fixtures. The only writes are on MailSettings.
| Area | Groups |
|---|---|
| Masters | RoleMaster, UserMaster, CustomerMaster, CustomerGroups, ZoneMaster, LocationMaster, FleetModels, VehicleMaster, ReasonsMaster, Tariff |
| Bookings & dispatch | BookingPlanner (getAllot20/getAllot60/getAllotMore60, getDrop15/getDrop30/getDrop60), AssignAllot, AutoAssignedBookings, PickupDrop, FreeVehicle, LockVehicle |
| Trips | RegularTrips, IntercityBookings, CancelledTrips, CCCollections |
| CRM | Enquiries, FollowUp, FeedbackComplaint, DndList, CallFlow |
| Fleet, owners, drivers | Vehicle, Owner, Driver, AttendanceBreak |
| Payments | PaymentList, PendingPayment |
| Reports | BookingReport, CancelledBooking, VehicleSummary, AttendanceReport, CustomersReport, TopCustomers, DispatcherWise, VehicleConsolidate, VehicleStatistics (getLoggedIn/getLoggedOut/getStatistics), PNR |
| Settings | SiteSettings, PaymentSettings, AnyVehicleSettings, PermissionSettings, MailSettings |
| Misc | Employees |
MailSettings is the only group with writes:
endpoints.MailSettings = {
getMailSettings: '/MailSettings/getMailSettings', // GET
saveMailSettings: '/MailSettings/saveMailSettings', // POST
sendTestEmail: '/MailSettings/sendTestEmail', // POST
};
await api.post(endpoints.MailSettings.saveMailSettings, payload);The auth header
Every request carries a single fixed header — the demo access key:
x_pvr_tech_studio_access: 123
createApi adds it automatically from the exported headers. The mock API requires it only
on writes; GET reads are open (and CDN-cached). Replace it with your real auth scheme (API
key, bearer token) when you wire up a real backend.
The bundled mock API
services/api is an Express 4 app (Node 20) that returns static JSON fixtures. Each
feature is a folder under src/routes / src/controllers; the controller wraps every fixture
in the same envelope. For RoleMaster:
// RoleMaster.controller.js
exports.getRoleMaster = async (req, res, next) => {
const formattedResponse = formatResponse({
status: 'success',
code: appConfig.responseCode.successCode, // 5000
message: appConfig.customMessages.successMsg, // "Data fetched successfully"
data: roleMasterData.data, // the array the UI renders
});
res.status(200).json(formattedResponse);
};Routes mount each feature under /taxi-crm/api/<Feature> inside the Express app (e.g.
app.use("/taxi-crm/api/RoleMaster", routes.RoleMaster)); in production the Firebase Hosting
rewrite forwards same-origin /api/** to that Cloud Run service. Start it locally with
npm run dev:api; it listens on port 8080.
So the live request and response for the driver list look like this:
GET http://localhost:8080/api/Driver/getDriver
Headers: x_pvr_tech_studio_access: 123
{
"status": "success",
"code": 5000,
"message": "Data fetched successfully",
"data": [
{ "driverId": "D-1001", "name": "Ar…", "mobile": "98…", "vehicleNo": "TN…", "city": "…" }
]
}The response envelope
Every endpoint returns the same four-field envelope (built by responseFormatter.js). Your
backend should match it so the editions keep working unchanged:
| Field | Meaning |
|---|---|
status | "success" or "failure". |
code | A numeric application code: 5000 success, 5001 created, 5002 retrieved, 5005 no data, 5008 failure (see config.js → responseCode). |
message | Human-readable message. |
data | The payload — for list pages, the array the table renders. |
Errors take a different shape — the centralized handler returns { error: { status, message, timestamp, … } } with Cache-Control: no-store.
How an edition reads it
A React/Vue component reads a list straight off res.data:
const api = createApi();
api.get(endpoints.Driver.getDriver)
.then((res) => setDrivers(res.data || []))
.catch((e) => setError(e.message));The HTML edition uses its own API_CONFIG object in assets/js/core/app.js rather than the
ES-module contract. It has an API_CONFIG.staticMode switch:
staticMode: false(source/demo default) —getUrl(path)joinsbaseUrl + path(http://localhost:8080/taxi-crm/apilocally,https://api.pvrtechstudio.com/taxi-crm/apiin the seller's demo), the live-API equivalent ofcreateApi.staticMode: true—getUrl(path)returns a bundledassets/data/{Feature}/{action}.jsonpath. The ThemeForest download ships this way (the build pre-renders the mock API's responses to JSON), so the HTML edition runs with no backend on any static server.
DataTables list pages pass getUrl(...) into the table's ajax option with dataSrc: "data".
See Tables and JavaScript Helpers.
Recipe: point an edition at your own backend
- React / Vue: pass your base to
createApi, e.g.createApi('https://api.yourcompany.com'), or rely on the same-origin/apiand point the hosting rewrite at your server. - HTML: in
assets/js/core/app.jssetAPI_CONFIG.staticMode = false(if you started from the static ThemeForest build) and pointAPI_CONFIG.baseUrlat your server. - Match the paths. Keep the
/{Feature}/{action}paths fromendpointsif you can — then nothing else changes. Otherwise edit the values to match your routes. - Return the envelope. Make each endpoint respond with
{ status, code, message, data }, with the row array underdata, and the field names each screen expects. - Set headers / auth. Replace
headers.x_pvr_tech_studio_accesswith your real auth header (API key, bearer token);createApiandAPI_CONFIG.headerssend it on every call.
Note: translations are fetched too
Separately from the API, the i18n engine loads locale JSON from assets/locales/ (8
languages). Some browsers block fetch() on file:// URLs, so serve the folder over HTTP if
text shows raw keys. Details in Internationalization.
Was this page helpful?
