ENGARAGE Open API — v1.0.0
Read and write your workshop data from your own systems.
Base URL: https://app.engarage.io/api/v1
The ENGARAGE Open API gives your own systems the same view of your workshop that the app has: customers, vehicles, bookings, work orders, quotations, inventory and procurement.
Availability
The API is included with the Pro plan. Keys are issued per workshop from Account Settings → API Docs & Keys, and every request is scoped to the workshop that issued the key — there is no way to read another workshop's data.
Authentication
Send your secret key on every request, either as an X-API-Key header or as
Authorization: Bearer <key>. Keys are shown once, at creation; store them
somewhere safe and never ship one in client-side code.
Environments
Every key is either live (eng_live_…) or sandbox (eng_test_…). A sandbox
key runs against an isolated fixture dataset with identical validation, envelopes and
error codes, so you can build and test a client — including writes — without touching
production data. Reset the sandbox at any time from the portal or with
POST /sandbox/reset.
Scopes
A key carries one of read, write or admin, and they nest: admin implies
write, which implies read. GET needs read, POST and PATCH need write, and
DELETE needs admin.
Pagination
List endpoints take page and limit (max 200) and return a meta block with
total, page, limit and total_pages. Sort with sort=field or sort=-field.
Rate limits
600 requests per minute per live key and 1200 per sandbox key.
Every response carries X-RateLimit-Limit and X-RateLimit-Remaining; a 429 carries
retry_after in seconds.
Errors
Failures always return the same envelope, so one handler covers them all:
{ "error": { "code": "validation_error", "message": "…", "field": "name" } }
Endpoints
Meta
GET/ping
Health check
Confirms the API is reachable and your key is valid. The cheapest call to wire up first.
Responses: 200, 401
{
"ok": true,
"version": "1.0.0",
"environment": "sandbox",
"time": "2026-09-08T04:20:00Z"
}
GET/me
Describe the calling key
Who you are: the workshop the key belongs to, its environment, scopes and rate limit. Useful for showing "connected as…" in your own UI.
Responses: 200, 401
{
"workshop": {
"id": 128,
"name": "Workshop Engarage Demo"
},
"key": {
"name": "Partner ERP Integration",
"environment": "sandbox",
"scopes": [
"read",
"write"
],
"last_used_at": "2026-09-08T04:19:12Z"
},
"plan": "pro",
"rate_limit": {
"limit": 1200,
"window": "1 minute"
}
}
POST/sandbox/reset
Reset the sandbox dataset
Throws away everything your sandbox key has created or changed and reseeds the fixtures. Rejected with 409 if called with a live key — there is deliberately no way to reset production.
Responses: 200, 409
{
"ok": true,
"message": "Sandbox dataset reset."
}
Customers
GET/customers
List customers
A customer owns vehicles and work orders. Phone number is the natural key most workshops search on, so it is indexed and filterable.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across name, phone and email. |
sort |
query | string | Sort field. Prefix with - for descending. |
phone |
query | string | Exact phone number match. |
email |
query | string | Exact email match. |
status |
query | integer | Record status. 1 = active. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789",
"country_code": "60",
"email": "[email protected]",
"gender": "female",
"dob": "1991-04-18",
"note": "Prefers WhatsApp reminders.",
"status": 1,
"vehicle_count": 2,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/customers
Create a customer
Creates a customer in the workshop that owns the key. Requires the write scope.
Request body:
{
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789",
"country_code": "60",
"email": "[email protected]",
"gender": "female",
"dob": "1991-04-18",
"note": "Prefers WhatsApp reminders."
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789",
"country_code": "60",
"email": "[email protected]",
"gender": "female",
"dob": "1991-04-18",
"note": "Prefers WhatsApp reminders.",
"status": 1,
"vehicle_count": 2,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/customers/{id}
Retrieve a customer
Fetch a single customer by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789",
"country_code": "60",
"email": "[email protected]",
"gender": "female",
"dob": "1991-04-18",
"note": "Prefers WhatsApp reminders.",
"status": 1,
"vehicle_count": 2,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/customers/{id}
Update a customer
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789"
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"name": "Nurul Aisyah binti Rahman",
"phone": "123456789",
"country_code": "60",
"email": "[email protected]",
"gender": "female",
"dob": "1991-04-18",
"note": "Prefers WhatsApp reminders.",
"status": 1,
"vehicle_count": 2,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
Vehicles
GET/vehicles
List vehicles
Vehicles hang off a customer. plate_no is what every counter workflow looks up, so filter on it rather than scanning the list.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across plate_no and chassis_no. |
sort |
query | string | Sort field. Prefix with - for descending. |
plate_no |
query | string | Exact registration-plate match. |
customer_id |
query | integer | Only vehicles owned by this customer. |
status |
query | integer | Record status. 1 = active. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"plate_no": "WXY 1234",
"chassis_no": "JHMCM56557C404453",
"ref_car_id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"year": "2021",
"next_service": "2026-12-01",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/vehicles
Create a vehicle
Creates a vehicle in the workshop that owns the key. Requires the write scope.
Request body:
{
"customer_id": 1,
"plate_no": "WXY 1234",
"ref_car_id": 1,
"chassis_no": "JHMCM56557C404453",
"year": "2021",
"next_service": "2026-12-01"
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"plate_no": "WXY 1234",
"chassis_no": "JHMCM56557C404453",
"ref_car_id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"year": "2021",
"next_service": "2026-12-01",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/vehicles/{id}
Retrieve a vehicle
Fetch a single vehicle by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"plate_no": "WXY 1234",
"chassis_no": "JHMCM56557C404453",
"ref_car_id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"year": "2021",
"next_service": "2026-12-01",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/vehicles/{id}
Update a vehicle
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"customer_id": 1,
"plate_no": "WXY 1234"
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"plate_no": "WXY 1234",
"chassis_no": "JHMCM56557C404453",
"ref_car_id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"year": "2021",
"next_service": "2026-12-01",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
DELETE/vehicles/{id}
Delete a vehicle
Soft-deletes the record. Requires the admin scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 204, 401, 403, 404
GET/vehicle-models
List vehicle models
Read-only reference data shared by every workshop. Look a model up here to get the ref_car_id that POST /vehicles requires.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across make and model. |
sort |
query | string | Sort field. Prefix with - for descending. |
make |
query | string | Exact manufacturer match. |
segment |
query | string | Exact segment match, e.g. "SUV". |
fuel_type |
query | string | Exact fuel-type match. |
status |
query | integer | Record status. 1 = active. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"oil_capacity": "3.2L",
"car_battery": "NS60",
"status": 1
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
GET/vehicle-models/{id}
Retrieve a vehicle model
Fetch a single vehicle model by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"make": "Perodua",
"model": "Myvi 1.5 AV",
"segment": "Hatchback",
"fuel_type": "Petrol",
"oil_capacity": "3.2L",
"car_battery": "NS60",
"status": 1
}
}
Bookings
GET/bookings
List bookings
A booking is a request for a slot. Accepting one creates a work order; this endpoint covers the request itself.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across remark. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Booking status. 1 = pending, 2 = accepted, 3 = rejected. |
customer_id |
query | integer | Only bookings for this customer. |
from |
query | string (date) | Only bookings at or after this date. |
to |
query | string (date) | Only bookings at or before this date. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"scheduled_at": "2026-09-15T09:30:00Z",
"remark": "Engine oil + filter, brakes squealing.",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/bookings
Create a booking
Creates a booking in the workshop that owns the key. Requires the write scope.
Request body:
{
"customer_id": 1,
"vehicle_id": 1,
"scheduled_at": "2026-09-15T09:30:00Z",
"remark": "Engine oil + filter, brakes squealing.",
"status": 1
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"scheduled_at": "2026-09-15T09:30:00Z",
"remark": "Engine oil + filter, brakes squealing.",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/bookings/{id}
Retrieve a booking
Fetch a single booking by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"scheduled_at": "2026-09-15T09:30:00Z",
"remark": "Engine oil + filter, brakes squealing.",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/bookings/{id}
Update a booking
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"customer_id": 1,
"vehicle_id": 1
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"scheduled_at": "2026-09-15T09:30:00Z",
"remark": "Engine oil + filter, brakes squealing.",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
Work Orders
GET/work-orders
List work orders
A work order is the spine of the system: it carries the vehicle, the customer, the assigned mechanic and bay, and every line item. Its status walks 1 → 10; see the status table in the guide.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across wo_no, invoice_no, quotation_no and complaint. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Work-order status, 1–10. |
customer_id |
query | integer | Only jobs for this customer. |
wo_no |
query | string | Exact work-order number. |
invoice_no |
query | string | Exact invoice number. |
from |
query | string (date) | Created at or after this date. |
to |
query | string (date) | Created at or before this date. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"wo_no": "WO-2609-0042",
"quotation_no": "QT-2609-0031",
"invoice_no": "INV-2609-0028",
"status": 7,
"status_label": "Paid",
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"mechanic_id": 3,
"bay_id": 2,
"complaint": "Brakes squealing on cold start.",
"remark": "Front pads replaced, discs skimmed.",
"mileage": "86540",
"total_payment": 486.5,
"payment_sst": 0,
"method": "card",
"booking_at": "2026-09-15T09:30:00Z",
"completed_at": "2026-09-15T15:10:00Z",
"invoiced_at": "2026-09-15T15:22:00Z",
"paid_at": "2026-09-15T15:40:00Z",
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
GET/work-orders/{id}
Retrieve a work order
Fetch a single work order by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"wo_no": "WO-2609-0042",
"quotation_no": "QT-2609-0031",
"invoice_no": "INV-2609-0028",
"status": 7,
"status_label": "Paid",
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"mechanic_id": 3,
"bay_id": 2,
"complaint": "Brakes squealing on cold start.",
"remark": "Front pads replaced, discs skimmed.",
"mileage": "86540",
"total_payment": 486.5,
"payment_sst": 0,
"method": "card",
"booking_at": "2026-09-15T09:30:00Z",
"completed_at": "2026-09-15T15:10:00Z",
"invoiced_at": "2026-09-15T15:22:00Z",
"paid_at": "2026-09-15T15:40:00Z",
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/work-orders/{id}
Update a work order
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"status": 7,
"mechanic_id": 3
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"wo_no": "WO-2609-0042",
"quotation_no": "QT-2609-0031",
"invoice_no": "INV-2609-0028",
"status": 7,
"status_label": "Paid",
"customer_id": 1,
"customer_name": "Nurul Aisyah binti Rahman",
"vehicle_id": 1,
"plate_no": "WXY 1234",
"mechanic_id": 3,
"bay_id": 2,
"complaint": "Brakes squealing on cold start.",
"remark": "Front pads replaced, discs skimmed.",
"mileage": "86540",
"total_payment": 486.5,
"payment_sst": 0,
"method": "card",
"booking_at": "2026-09-15T09:30:00Z",
"completed_at": "2026-09-15T15:10:00Z",
"invoiced_at": "2026-09-15T15:22:00Z",
"paid_at": "2026-09-15T15:40:00Z",
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/work-orders/{id}/items
Line items on a work order
Parts, services, packages and miscellaneous charges billed on this job.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": [
{
"id": 5501,
"type": "part",
"part_id": 812,
"service_id": null,
"package_id": null,
"quantity": 4,
"total_price": 168,
"total_discount": 0,
"tax_rate": 0
}
]
}
Quotations
GET/quotations
List quotations
A work order can carry several quotations across revisions; the one with status 2 is the accepted one.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across quotation_no. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Quotation status. 2 = accepted/converted. |
work_order_id |
query | integer | Only quotations on this work order. |
quotation_no |
query | string | Exact quotation number. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"quotation_no": "QT-2609-0031",
"work_order_id": 42,
"wo_no": "WO-2609-0042",
"customer_id": 1,
"status": 2,
"discount": 20,
"deposit": 100,
"deposit_method": "cash",
"deposit_at": "2026-09-15T10:05:00Z",
"total": 486.5,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
GET/quotations/{id}
Retrieve a quotation
Fetch a single quotation by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"quotation_no": "QT-2609-0031",
"work_order_id": 42,
"wo_no": "WO-2609-0042",
"customer_id": 1,
"status": 2,
"discount": 20,
"deposit": 100,
"deposit_method": "cash",
"deposit_at": "2026-09-15T10:05:00Z",
"total": 486.5,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
Inventory
GET/parts
List parts
Your inventory. quantity is on-hand stock; it moves when work orders are paid, so treat it as authoritative rather than caching it.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across name, part_no, brand and model. |
sort |
query | string | Sort field. Prefix with - for descending. |
part_no |
query | string | Exact part number. |
brand |
query | string | Exact brand match. |
supplier_id |
query | integer | Only parts from this supplier. |
status |
query | integer | Record status. 1 = active. |
low_stock |
query | boolean | When true, only parts at or below their stock-alert threshold. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA",
"brand": "Denso",
"model": "Myvi",
"variant": "1.5L",
"description": "Spin-on oil filter.",
"unit": "pcs",
"bin_number": "A-04-2",
"cost_price": 12.5,
"price": 24,
"quantity": 36,
"stock_alert_threshold": 10,
"supplier_id": 4,
"is_low_stock": false,
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/parts
Create a part
Creates a part in the workshop that owns the key. Requires the write scope.
Request body:
{
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA",
"brand": "Denso",
"model": "Myvi",
"variant": "1.5L",
"description": "Spin-on oil filter.",
"unit": "pcs",
"bin_number": "A-04-2",
"cost_price": 12.5,
"price": 24,
"quantity": 36,
"stock_alert_threshold": 10,
"supplier_id": 4
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA",
"brand": "Denso",
"model": "Myvi",
"variant": "1.5L",
"description": "Spin-on oil filter.",
"unit": "pcs",
"bin_number": "A-04-2",
"cost_price": 12.5,
"price": 24,
"quantity": 36,
"stock_alert_threshold": 10,
"supplier_id": 4,
"is_low_stock": false,
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/parts/{id}
Retrieve a part
Fetch a single part by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA",
"brand": "Denso",
"model": "Myvi",
"variant": "1.5L",
"description": "Spin-on oil filter.",
"unit": "pcs",
"bin_number": "A-04-2",
"cost_price": 12.5,
"price": 24,
"quantity": 36,
"stock_alert_threshold": 10,
"supplier_id": 4,
"is_low_stock": false,
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/parts/{id}
Update a part
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA"
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"name": "Engine Oil Filter",
"part_no": "OF-15400-RTA",
"brand": "Denso",
"model": "Myvi",
"variant": "1.5L",
"description": "Spin-on oil filter.",
"unit": "pcs",
"bin_number": "A-04-2",
"cost_price": 12.5,
"price": 24,
"quantity": 36,
"stock_alert_threshold": 10,
"supplier_id": 4,
"is_low_stock": false,
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
DELETE/parts/{id}
Delete a part
Soft-deletes the record. Requires the admin scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 204, 401, 403, 404
GET/suppliers
List suppliers
Suppliers referenced by parts and purchase orders.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across name, company_reg, email and phone_no. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Record status. 1 = active. |
state |
query | string | Exact state match. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456",
"sales_p": "Mr Tan",
"phone_no": "0377881234",
"email": "[email protected]",
"address_1": "Lot 12, Jalan Perindustrian 3",
"address_2": null,
"postcode": "47100",
"city": "Puchong",
"state": "Selangor",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/suppliers
Create a supplier
Creates a supplier in the workshop that owns the key. Requires the write scope.
Request body:
{
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456",
"sales_p": "Mr Tan",
"phone_no": "0377881234",
"email": "[email protected]",
"address_1": "Lot 12, Jalan Perindustrian 3",
"address_2": null,
"postcode": "47100",
"city": "Puchong",
"state": "Selangor"
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456",
"sales_p": "Mr Tan",
"phone_no": "0377881234",
"email": "[email protected]",
"address_1": "Lot 12, Jalan Perindustrian 3",
"address_2": null,
"postcode": "47100",
"city": "Puchong",
"state": "Selangor",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/suppliers/{id}
Retrieve a supplier
Fetch a single supplier by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456",
"sales_p": "Mr Tan",
"phone_no": "0377881234",
"email": "[email protected]",
"address_1": "Lot 12, Jalan Perindustrian 3",
"address_2": null,
"postcode": "47100",
"city": "Puchong",
"state": "Selangor",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/suppliers/{id}
Update a supplier
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456"
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"name": "Southern Auto Parts Sdn Bhd",
"company_reg": "201801023456",
"sales_p": "Mr Tan",
"phone_no": "0377881234",
"email": "[email protected]",
"address_1": "Lot 12, Jalan Perindustrian 3",
"address_2": null,
"postcode": "47100",
"city": "Puchong",
"state": "Selangor",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
DELETE/suppliers/{id}
Delete a supplier
Soft-deletes the record. Requires the admin scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 204, 401, 403, 404
GET/purchase-orders
List purchase orders
Read-only view of procurement. Raising and receiving stock stays in the app so the stock ledger cannot be bypassed.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across po_no and supplier_invoice_no. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Purchase-order status. |
supplier_id |
query | integer | Only orders to this supplier. |
po_no |
query | string | Exact purchase-order number. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"po_no": "PO-2609-0011",
"supplier_id": 4,
"supplier_name": "Southern Auto Parts Sdn Bhd",
"supplier_invoice_no": "SAP-88213",
"total": 1420,
"tax_rate": 0,
"discount": 0,
"shipping_cost": 25,
"status": 3,
"notes": "Monthly filter restock.",
"ordered_at": "2026-09-01T08:00:00Z",
"approved_at": "2026-09-01T09:12:00Z",
"paid_at": null,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
GET/purchase-orders/{id}
Retrieve a purchase order
Fetch a single purchase order by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"po_no": "PO-2609-0011",
"supplier_id": 4,
"supplier_name": "Southern Auto Parts Sdn Bhd",
"supplier_invoice_no": "SAP-88213",
"total": 1420,
"tax_rate": 0,
"discount": 0,
"shipping_cost": 25,
"status": 3,
"notes": "Monthly filter restock.",
"ordered_at": "2026-09-01T08:00:00Z",
"approved_at": "2026-09-01T09:12:00Z",
"paid_at": null,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
Catalogue
GET/services
List services
The service catalogue billed on work orders and quotations.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across name, service_no and category. |
sort |
query | string | Sort field. Prefix with - for descending. |
category |
query | string | Exact category match. |
status |
query | integer | Record status. 1 = active. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"name": "Engine Oil Service",
"service_no": "SRV-001",
"category": "Engine",
"price": 80,
"price_sst": 80,
"sst": 0,
"hours": 0.75,
"skill_level": "junior",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
POST/services
Create a service
Creates a service in the workshop that owns the key. Requires the write scope.
Request body:
{
"name": "Engine Oil Service",
"service_no": "SRV-001",
"category": "Engine",
"price": 80,
"price_sst": 80,
"sst": 0,
"hours": 0.75,
"skill_level": "junior"
}
Responses: 201, 401, 403, 422
{
"data": {
"id": 1,
"name": "Engine Oil Service",
"service_no": "SRV-001",
"category": "Engine",
"price": 80,
"price_sst": 80,
"sst": 0,
"hours": 0.75,
"skill_level": "junior",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
GET/services/{id}
Retrieve a service
Fetch a single service by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"name": "Engine Oil Service",
"service_no": "SRV-001",
"category": "Engine",
"price": 80,
"price_sst": 80,
"sst": 0,
"hours": 0.75,
"skill_level": "junior",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
PATCH/services/{id}
Update a service
Partial update — send only the fields you want to change. Requires the write scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Request body:
{
"name": "Engine Oil Service",
"service_no": "SRV-001"
}
Responses: 200, 401, 404, 422
{
"data": {
"id": 1,
"name": "Engine Oil Service",
"service_no": "SRV-001",
"category": "Engine",
"price": 80,
"price_sst": 80,
"sst": 0,
"hours": 0.75,
"skill_level": "junior",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
DELETE/services/{id}
Delete a service
Soft-deletes the record. Requires the admin scope.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 204, 401, 403, 404
Workshop
GET/mechanics
List mechanics
Read-only roster used to resolve mechanic_id on work orders.
| Parameter | In | Type | Description |
|---|---|---|---|
page |
query | integer | Page to fetch, 1-based. |
limit |
query | integer | Records per page. |
search |
query | string | Partial match across name, nickname, email and reg_no. |
sort |
query | string | Sort field. Prefix with - for descending. |
status |
query | integer | Record status. 1 = active. |
Responses: 200, 401, 403, 422, 429
{
"data": [
{
"id": 1,
"name": "Mohd Faizal bin Osman",
"nickname": "Faizal",
"email": "[email protected]",
"phone_no": "0198887766",
"reg_no": "MEC-003",
"skill": "Brakes, suspension",
"qualification": "SKM Level 3",
"exp_year": "8",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
],
"meta": {
"total": 8,
"page": 1,
"limit": 50,
"total_pages": 1
}
}
GET/mechanics/{id}
Retrieve a mechanic
Fetch a single mechanic by id. Ids from another workshop return 404.
| Parameter | In | Type | Description |
|---|---|---|---|
id |
path | integer | Record id. |
Responses: 200, 401, 404
{
"data": {
"id": 1,
"name": "Mohd Faizal bin Osman",
"nickname": "Faizal",
"email": "[email protected]",
"phone_no": "0198887766",
"reg_no": "MEC-003",
"skill": "Brakes, suspension",
"qualification": "SKM Level 3",
"exp_year": "8",
"status": 1,
"created_at": "2026-09-01T08:15:00Z",
"updated_at": "2026-09-06T11:42:00Z"
}
}
Schemas
PageMeta
Pagination block returned by every list endpoint.
| Field | Type | Description |
|---|---|---|
total |
integer | Total records matching the query. |
page |
integer | Current page (1-based). |
limit |
integer | Records per page. |
total_pages |
integer | Number of pages available. |
Error
Every failure uses this envelope.
| Field | Type | Description |
|---|---|---|
error |
object |
KeyContext
| Field | Type | Description |
|---|---|---|
workshop |
object | |
key |
object | |
plan |
string | |
rate_limit |
object |
Customer
People and companies your workshop serves.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique customer id. |
name |
string | Full name or company name. |
phone |
string, null | Contact number, without the country code. |
country_code |
string, null | Dialling code for phone, e.g. "60". |
email |
string, null (email) | Contact email. |
gender |
string, null | Free-text gender as captured at the counter. |
dob |
string, null (date) | Date of birth. |
note |
string, null | Internal note shown to counter staff. |
status |
integer, null | Record status. 1 = active. |
vehicle_count |
integer | Vehicles currently registered to this customer. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
CustomerInput
| Field | Type | Description |
|---|---|---|
name |
string | Full name or company name. |
phone |
string | Contact number, without the country code. |
country_code |
string | Dialling code for phone. |
email |
string | Contact email. |
gender |
string | Gender. |
dob |
string | Date of birth (YYYY-MM-DD). |
note |
string | Internal note. |
Vehicle
Vehicles registered against your customers.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique vehicle id. |
customer_id |
integer | Owning customer. |
customer_name |
string, null | Owning customer name (read-only convenience). |
plate_no |
string | Registration plate. |
chassis_no |
string, null | VIN / chassis number. |
ref_car_id |
integer, null | Catalogue model id — see GET /vehicle-models. |
make |
string, null | Manufacturer, from the ENGARAGE vehicle catalogue. |
model |
string, null | Model, from the ENGARAGE vehicle catalogue. |
segment |
string, null | Vehicle segment, e.g. "SUV". |
fuel_type |
string, null | Petrol, diesel, hybrid or EV. |
year |
string, null | Model year. |
next_service |
string, null (date) | Next service due date. |
status |
integer, null | Record status. 1 = active. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
VehicleInput
| Field | Type | Description |
|---|---|---|
customer_id |
integer | Owning customer id. |
plate_no |
string | Registration plate. |
ref_car_id |
integer | Catalogue model id — look it up with GET /vehicle-models. |
chassis_no |
string | VIN / chassis number. |
year |
string | Model year. |
next_service |
string | Next service due date. |
VehicleModel
ENGARAGE's shared make/model catalogue.
| Field | Type | Description |
|---|---|---|
id |
integer | Catalogue id — this is the ref_car_id used when creating a vehicle. |
make |
string, null | Manufacturer. |
model |
string, null | Model and variant. |
segment |
string, null | Vehicle segment, e.g. "SUV". |
fuel_type |
string, null | Petrol, diesel, hybrid or EV. |
oil_capacity |
string, null | Engine oil capacity, as published by the manufacturer. |
car_battery |
string, null | Recommended battery specification. |
status |
integer, null | Record status. 1 = active. |
Booking
Appointments customers have made with your workshop.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique booking id. |
customer_id |
integer, null | Customer who booked. |
customer_name |
string, null | Customer name (read-only convenience). |
vehicle_id |
integer, null | Vehicle being brought in. |
plate_no |
string, null | Vehicle plate (read-only convenience). |
scheduled_at |
string, null (date-time) | Requested slot. |
remark |
string, null | What the customer wants done. |
status |
integer, null | Booking status. 1 = pending, 2 = accepted, 3 = rejected. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
BookingInput
| Field | Type | Description |
|---|---|---|
customer_id |
integer | Customer id. |
vehicle_id |
integer | Vehicle id. |
scheduled_at |
string | Requested slot (ISO-8601). |
remark |
string | What the customer wants done. |
status |
integer | Booking status. |
WorkOrder
Jobs on the shop floor, from booking through to paid.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique work-order id. |
wo_no |
string, null | Human-readable work-order number. |
quotation_no |
string, null | Quotation number, once quoted. |
invoice_no |
string, null | Invoice number, once invoiced. |
status |
integer | Status code 1–10. |
status_label |
string | Human label for status. |
customer_id |
integer, null | Customer the job is for. |
customer_name |
string, null | Customer name. |
vehicle_id |
integer, null | Vehicle in the bay. |
plate_no |
string, null | Vehicle plate. |
mechanic_id |
integer, null | Assigned mechanic. |
bay_id |
integer, null | Assigned bay. |
complaint |
string, null | The customer's reported problem. |
remark |
string, null | Internal note. |
mileage |
string, null | Odometer reading on arrival. |
total_payment |
number, null | Invoice total, including tax. |
payment_sst |
number, null | Tax portion of the total. |
method |
string, null | Payment method, once paid. |
booking_at |
string, null (date-time) | When the job was booked. |
completed_at |
string, null (date-time) | When work finished. |
invoiced_at |
string, null (date-time) | When the invoice was raised. |
paid_at |
string, null (date-time) | When payment was received. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
WorkOrderInput
| Field | Type | Description |
|---|---|---|
status |
integer | Move the job along the status ladder. |
mechanic_id |
integer | Assign a mechanic. |
bay_id |
integer | Assign a bay. |
remark |
string | Internal note. |
complaint |
string | The customer's reported problem. |
mileage |
string | Odometer reading. |
WorkOrderItems
Line items on a work order
| Field | Type | Description |
|---|---|---|
id |
integer | Line-item id. |
type |
string, null | What is being billed: part, package, service or misc. |
part_id |
integer, null | Inventory part, when type is part. |
service_id |
integer, null | Service, when type is service. |
package_id |
integer, null | Package, when type is package. |
quantity |
number, null | Quantity billed. |
total_price |
number, null | Line total before discount. |
total_discount |
number, null | Discount applied to the line. |
tax_rate |
number, null | Tax rate applied, as a percentage. |
Quotation
Priced estimates issued against a work order.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique quotation id. |
quotation_no |
string, null | Human-readable quotation number. |
work_order_id |
integer, null | Work order this quotes. |
wo_no |
string, null | Work-order number. |
customer_id |
integer, null | Customer quoted. |
status |
integer, null | Quotation status. 2 = accepted. |
discount |
number, null | Discount value applied. |
deposit |
number, null | Deposit collected. |
deposit_method |
string, null | How the deposit was paid. |
deposit_at |
string, null (date-time) | When the deposit was collected. |
total |
number, null | Quoted total. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
Part
Stocked parts and consumables.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique part id. |
name |
string | Part name. |
part_no |
string, null | Manufacturer or internal part number. |
brand |
string, null | Brand. |
model |
string, null | Vehicle model this fits. |
variant |
string, null | Variant / specification. |
description |
string, null | Longer description. |
unit |
string, null | Unit of measure, e.g. "pcs", "litre". |
bin_number |
string, null | Storage location. |
cost_price |
number, null | What you pay your supplier. |
price |
number, null | What you charge the customer. |
quantity |
number, null | On-hand stock. |
stock_alert_threshold |
number, null | Level at which the part counts as low stock. |
supplier_id |
integer, null | Default supplier. |
is_low_stock |
boolean | True when on-hand stock is at or below the threshold. |
status |
integer, null | Record status. 1 = active. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
PartInput
| Field | Type | Description |
|---|---|---|
name |
string | Part name. |
part_no |
string | Part number. Must be unique within your workshop. |
brand |
string | Brand. |
model |
string | Vehicle model this fits. |
variant |
string | Variant / specification. |
description |
string | Longer description. |
unit |
string | Unit of measure. |
bin_number |
string | Storage location. |
cost_price |
number | Supplier cost. |
price |
number | Selling price. |
quantity |
number | On-hand stock. |
stock_alert_threshold |
number | Low-stock threshold. |
supplier_id |
integer | Default supplier. |
Service
Labour and service items you sell.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique service id. |
name |
string | Service name. |
service_no |
string, null | Internal service code. |
category |
string, null | Grouping, e.g. "Engine". |
price |
number, null | Price before tax. |
price_sst |
number, null | Price including tax. |
sst |
number, null | Tax rate applied, as a percentage. |
hours |
number, null | Standard labour hours. |
skill_level |
string, null | Skill required to perform it. |
status |
integer, null | Record status. 1 = active. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
ServiceInput
| Field | Type | Description |
|---|---|---|
name |
string | Service name. |
service_no |
string | Internal service code. |
category |
string | Grouping. |
price |
number | Price before tax. |
price_sst |
number | Price including tax. |
sst |
number | Tax rate percentage. |
hours |
number | Standard labour hours. |
skill_level |
string | Skill required. |
Supplier
Vendors you buy parts from.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique supplier id. |
name |
string | Supplier name. |
company_reg |
string, null | Company registration number. |
sales_p |
string, null | Sales contact person. |
phone_no |
string, null | Contact number. |
email |
string, null (email) | Contact email. |
address_1 |
string, null | Address line 1. |
address_2 |
string, null | Address line 2. |
postcode |
string, null | Postcode. |
city |
string, null | City. |
state |
string, null | State. |
status |
integer, null | Record status. 1 = active. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
SupplierInput
| Field | Type | Description |
|---|---|---|
name |
string | Supplier name. |
company_reg |
string | Company registration number. |
sales_p |
string | Sales contact person. |
phone_no |
string | Contact number. |
email |
string | Contact email. |
address_1 |
string | Address line 1. |
address_2 |
string | Address line 2. |
postcode |
string | Postcode. |
city |
string | City. |
state |
string | State. |
PurchaseOrder
Orders raised against your suppliers.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique purchase-order id. |
po_no |
string, null | Purchase-order number. |
supplier_id |
integer, null | Supplier ordered from. |
supplier_name |
string, null | Supplier name. |
supplier_invoice_no |
string, null | The supplier's own invoice number. |
total |
number, null | Order total. |
tax_rate |
number, null | Tax rate applied, as a percentage. |
discount |
number, null | Discount applied. |
shipping_cost |
number, null | Shipping charged. |
status |
integer, null | Purchase-order status. |
notes |
string, null | Internal note. |
ordered_at |
string, null (date-time) | When the order was raised. |
approved_at |
string, null (date-time) | When it was approved. |
paid_at |
string, null (date-time) | When it was paid. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
Mechanic
Technicians on your team.
| Field | Type | Description |
|---|---|---|
id |
integer | Unique mechanic id. |
name |
string, null | Full name. |
nickname |
string, null | Name shown on the shop-floor board. |
email |
string, null (email) | Email. |
phone_no |
string, null | Contact number. |
reg_no |
string, null | Staff / registration number. |
skill |
string, null | Skills, as captured on the profile. |
qualification |
string, null | Qualifications. |
exp_year |
string, null | Years of experience. |
status |
integer, null | Record status. 1 = active. |
created_at |
string (date-time) | When the record was created (ISO-8601, UTC). |
updated_at |
string (date-time) | When the record last changed (ISO-8601, UTC). |
Generated from the ENGARAGE OpenAPI specification on Wed, Oct 21, 2026 11:28 AM.