HaloPSA Asset Management
Overview
Assets (also called Configuration Items or CIs) in HaloPSA represent managed devices, software, and other trackable items. Effective asset management is crucial for MSPs to track what's deployed at client sites, manage hardware lifecycle, and link service tickets to affected equipment.
Key Concepts
Asset
The primary entity representing a managed device or configuration item.
| Field | Type | Required | Description |
|---|---|---|---|
id | int | System | Unique identifier |
inventory_number | string | No | Internal asset tag |
client_id | int | Yes | Associated client |
site_id | int | No | Physical location |
user_id | int | No | Assigned user |
devicetype_id | int | No | Asset type category |
status_id | int | No | Asset status |
Asset Identification Fields
| Field | Type | Required | Description |
|---|---|---|---|
devicename | string(255) | Yes | Device hostname/name |
serialnumber | string | No | Manufacturer serial |
assettag | string | No | Company asset tag |
barcode | string | No | Barcode identifier |
macaddress | string | No | Network MAC address |
Asset Details
| Field | Type | Required | Description |
|---|---|---|---|
manufacturer | string | No | Device manufacturer |
model | string | No | Device model |
operatingsystem | string | No | OS name/version |
operatingsystemversion | string | No | OS detailed version |
ipaddress | string | No | IP address |
Asset Lifecycle Fields
| Field | Type | Required | Description |
|---|---|---|---|
purchasedate | date | No | Date acquired |
purchaseprice | decimal | No | Purchase cost |
warrantyexpires | date | No | Warranty end date |
lastauditdate | datetime | No | Last RMM sync |
inactive | bool | No | Active status |
Contract & Billing
| Field | Type | Required | Description |
|---|---|---|---|
contract_id | int | No | Associated contract |
supplier_id | int | No | Vendor/supplier |
notes | text | No | Asset notes |
Asset Types
Common asset types in HaloPSA:
| Type ID | Name | Examples |
|---|---|---|
| 1 | Workstation | Desktop, laptop |
| 2 | Server | Physical/virtual server |
| 3 | Network Device | Router, switch, firewall |
| 4 | Printer | Network/local printer |
| 5 | Mobile Device | Phone, tablet |
| 6 | Software | License, subscription |
| 7 | Other | Miscellaneous |
Note: Asset types are configurable per instance. Query /api/AssetType for your values.
Asset Status
| Status ID | Name | Description |
|---|---|---|
| 1 | Active | In production use |
| 2 | Spare | Available backup |
| 3 | In Repair | Under maintenance |
| 4 | Retired | End of life |
| 5 | On Order | Pending delivery |
| 6 | Lost/Stolen | Missing |
Note: Status IDs are configurable per instance. Query /api/AssetStatus for your values.
API Patterns
Creating an Asset
POST /api/Asset
Authorization: Bearer {token}
Content-Type: application/json
[
{
"devicename": "ACME-WS-001",
"client_id": 123,
"site_id": 456,
"user_id": 789,
"devicetype_id": 1,
"status_id": 1,
"manufacturer": "Dell",
"model": "OptiPlex 7090",
"serialnumber": "ABC123XYZ",
"assettag": "ACME-001",
"operatingsystem": "Windows 11 Pro",
"operatingsystemversion": "22H2",
"ipaddress": "192.168.1.100",
"macaddress": "00:1A:2B:3C:4D:5E",
"purchasedate": "2024-01-15",
"purchaseprice": 1299.99,
"warrantyexpires": "2027-01-15"
}
]
Response
{
"assets": [
{
"id": 5001,
"devicename": "ACME-WS-001",
"client_id": 123,
"client_name": "Acme Corporation",
"site_name": "Acme HQ",
"status_id": 1,
"status_name": "Active"
}
]
}
Searching Assets
By client:
GET /api/Asset?client_id=123
By site:
GET /api/Asset?site_id=456
By type:
GET /api/Asset?devicetype_id=1
Active assets only:
GET /api/Asset?inactive=false
Search by name:
GET /api/Asset?search=ACME-WS
Warranty expiring soon:
GET /api/Asset?warrantyexpires_before=2024-03-31
Getting a Single Asset
GET /api/Asset/5001
With related data:
GET /api/Asset/5001?includedetails=true
Updating an Asset
POST /api/Asset
Authorization: Bearer {token}
Content-Type: application/json
[
{
"id": 5001,
"status_id": 3,
"notes": "Sent to vendor for motherboard repair"
}
]
Bulk Asset Update
[
{ "id": 5001, "status_id": 1 },
{ "id": 5002, "status_id": 1 },
{ "id": 5003, "status_id": 4, "inactive": true }
]
Asset Relationships
Linking Asset to Ticket
When creating or updating a ticket, reference the asset:
[
{
"summary": "Workstation not booting",
"client_id": 123,
"asset_id": 5001,
"tickettype_id": 1,
"status_id": 1
}
]
Linking Assets Together
Parent-child relationships (e.g., server and its VMs):
[
{
"id": 5010,
"parent_id": 5009,
"notes": "VM hosted on ACME-SRV-001"
}
]
Asset History
Track changes via the audit log or custom fields.
RMM Integration
HaloPSA integrates with RMM tools to auto-sync assets.
Auto-Sync Fields
When integrated with an RMM, these fields typically auto-populate:
- •
devicename - •
operatingsystem - •
operatingsystemversion - •
ipaddress - •
macaddress - •
lastauditdate
RMM Identifier
| Field | Description |
|---|---|
ncentral_device_id | N-central device ID |
datto_device_id | Datto RMM device ID |
connectwise_device_id | Automate device ID |
Matching Assets
async function matchOrCreateAsset(rmmDevice) {
// 1. Try to match by RMM ID
let asset = await findAssetByRmmId(rmmDevice.id);
if (!asset) {
// 2. Try to match by serial number
asset = await findAssetBySerial(rmmDevice.serialNumber);
}
if (!asset) {
// 3. Try to match by hostname + client
asset = await findAssetByHostname(
rmmDevice.hostname,
rmmDevice.clientId
);
}
if (asset) {
// Update existing
return updateAsset(asset.id, rmmDevice);
} else {
// Create new
return createAsset(rmmDevice);
}
}
Common Workflows
Hardware Procurement
- •
Create asset as "On Order"
json[{ "devicename": "New Laptop", "status_id": 5, "client_id": 123 }] - •
Receive and configure
- •Update with serial, asset tag
- •Install software
- •Update status to "Spare"
- •
Deploy to user
- •Assign
user_idandsite_id - •Update status to "Active"
- •Create deployment ticket
- •Assign
Hardware Refresh
- •
Identify aging assets
httpGET /api/Asset?purchasedate_before=2020-01-01&inactive=false
- •
Generate refresh report
- •List assets over X years old
- •Calculate replacement cost
- •
Plan replacement
- •Order new equipment
- •Schedule deployment tickets
- •Update old assets to "Retired"
Warranty Management
- •
Find expiring warranties
httpGET /api/Asset?warrantyexpires_before=2024-06-30&warrantyexpires_after=2024-01-01
- •
Generate renewal quotes
- •
Update warranty dates after renewal
Asset Audit
async function auditClientAssets(clientId) {
const assets = await getClientAssets(clientId);
const report = {
total: assets.length,
active: 0,
noWarranty: [],
missingSerial: [],
oldOS: []
};
assets.forEach(asset => {
if (!asset.inactive) report.active++;
if (!asset.warrantyexpires || new Date(asset.warrantyexpires) < new Date()) {
report.noWarranty.push(asset);
}
if (!asset.serialnumber) {
report.missingSerial.push(asset);
}
if (asset.operatingsystem?.includes('Windows 10') &&
new Date(asset.purchasedate) < new Date('2020-01-01')) {
report.oldOS.push(asset);
}
});
return report;
}
Error Handling
Common API Errors
| Code | Message | Resolution |
|---|---|---|
| 400 | devicename required | Asset must have a name |
| 400 | client_id required | Asset must be linked to client |
| 400 | Invalid devicetype_id | Query /api/AssetType for valid IDs |
| 404 | Asset not found | Verify asset ID exists |
| 409 | Duplicate serial number | Serial already in use |
Validation Patterns
function validateAsset(asset) {
const errors = [];
if (!asset.devicename || asset.devicename.trim() === '') {
errors.push('Device name is required');
}
if (!asset.client_id) {
errors.push('Client ID is required');
}
if (asset.macaddress && !isValidMac(asset.macaddress)) {
errors.push('Invalid MAC address format');
}
if (asset.ipaddress && !isValidIP(asset.ipaddress)) {
errors.push('Invalid IP address format');
}
return {
isValid: errors.length === 0,
errors
};
}
Best Practices
- •Use consistent naming - Establish hostname conventions (CLIENT-TYPE-###)
- •Track serials - Essential for warranty and vendor support
- •Link to clients - Every asset should have a client_id
- •Update status promptly - Keeps inventory accurate
- •Document lifecycle - Purchase date, warranty, refresh date
- •Sync with RMM - Automated updates reduce manual effort
- •Regular audits - Compare RMM data vs PSA records
- •Track costs - Purchase price and depreciation
Asset Reports
Assets by Type
GET /api/Asset?groupby=devicetype_id&count=true
Assets by Client
GET /api/Asset?groupby=client_id&count=true
Asset Value by Client
async function getAssetValueByClient() {
const clients = await fetchAllClients();
const results = [];
for (const client of clients) {
const assets = await getClientAssets(client.id);
const totalValue = assets.reduce(
(sum, a) => sum + (a.purchaseprice || 0), 0
);
results.push({
client_id: client.id,
client_name: client.name,
asset_count: assets.length,
total_value: totalValue
});
}
return results.sort((a, b) => b.total_value - a.total_value);
}
Related Skills
- •HaloPSA Tickets - Link assets to tickets
- •HaloPSA Clients - Client and site management
- •HaloPSA Contracts - Asset billing and coverage
- •HaloPSA API Patterns - Authentication and queries