HaloPSA Client Management
Overview
Clients (customers) are the foundation of HaloPSA. All tickets, contracts, assets, and invoices are associated with clients. Proper client data management is critical for accurate service delivery and billing.
Anti-triggers
HaloPSA calls end-user contacts Users. That word does not mean a HaloPSA login, and it does not mean a technician.
- Your own technicians and teams — those are agents, a separate
entity with its own IDs; use
halopsa-agents. Assigning a ticket needs anagent_id, never auser_id. - The same customer in another system — a Freshdesk company, a
ConnectWise company, or an Autotask company is a different record with
different required fields; use
freshdesk-contacts-companies,connectwise-psa-companies, orautotask-crm. Do not assume IDs or domains map across. - Microsoft 365 or Entra user accounts — mailbox, licence, and
identity questions are
cipp-usersorcipp-mailboxes; a HaloPSA User is a CRM contact record with no directory presence. - What the client is entitled to — coverage, rates, and prepaid hours
are
halopsa-contracts; what they have been billed ishalopsa-invoices.
Key Concepts
Three linked entities make up the CRM layer:
| Entity | Endpoint | Key relationship |
|---|---|---|
| Client | /api/Client |
Root record; owns sites, contacts, tickets, assets, contracts |
| Site | /api/Site |
client_id -> Client; one site may be flagged main_site |
| Contact (User) | /api/Users |
client_id -> Client, optional site_id -> Site |
Most-used client fields: id, name (required), emailaddress, phonenumber,
website, accountmanager_id, inactive, client_to_invoice, toplevel_id.
Most-used contact fields: name (required), client_id (required), site_id,
emailaddress, jobtitle, isimportantcontact, inactive.
Clients are classified (Customer, Prospect, Lead, Partner, Vendor) via custom fields and categories rather than a built-in type enum.
See references/fields.md for the complete field reference for clients, sites, contacts, and client types.
Client Hierarchy
HaloPSA supports parent-child client relationships via two separate fields:
client_to_invoice— the client that receives the invoicetoplevel_id— the top-level parent in the reporting hierarchy
Set both when a child should both roll up for reporting and bill to the parent.
Hierarchy Use Cases
- Franchise operations - Parent company, individual locations
- Multi-site organizations - Headquarters with branch offices
- Billing consolidation - Invoice parent, service children
API Patterns
- Create and update use the same call.
POST /api/Client(also/api/Site,/api/Users) creates when noidis present and updates whenidis supplied. There is noPUT/PATCH. - The body is always a JSON array, even for a single record. This is also how you batch multiple creates/updates in one request.
- Updates are partial — send only
idplus the fields you are changing. - Related data is opt-in on single-record GETs:
GET /api/Client/123?includesites=true&includeusers=true. - Pagination and sorting use
page_no,page_size,order,orderdesc.
See references/api.md for full request/response examples covering client, site, and contact create/search/update.
Common Workflows
Client Onboarding
Create client record
- Set name and contact information
- Assign account manager
- Configure billing settings
Create primary site
- Add main location address
- Set as main_site
Create primary contact
- Add key stakeholder
- Set as important contact
- Verify email address
Set up contract
- Link to client
- Define service levels
- Configure billing
Deploy assets (if applicable)
- Link devices to client
- Associate with site
Search for an existing record by name or email before each create step — HaloPSA does not enforce uniqueness on client names or contact emails across clients. See references/examples.md for a contact-onboarding routine that does the duplicate check.
Client Deactivation
When a client churns:
Mark client inactive
[{ "id": 123, "inactive": true }]Close open tickets
- Resolve or cancel pending tickets
- Document reason
End contracts
- Update contract end dates
- Process final billing
Update assets
- Return or reassign devices
- Update RMM status
Never delete a client that has related records — HaloPSA returns 409 and deactivation is the supported path.
Error Handling
| Code | Message | Resolution |
|---|---|---|
| 400 | Name is required | Client must have a name |
| 400 | Invalid client_id | Parent client doesn't exist |
| 400 | Duplicate email | Contact email already in use |
| 404 | Client not found | Verify client ID |
| 409 | Cannot delete - has related records | Deactivate instead |
See references/examples.md for client validation and duplicate-detection helpers.
Data Quality Queries
Find clients without contacts
GET /api/Client?hasusers=false&inactive=false
Find contacts without email
GET /api/Users?emailaddress=null&inactive=false
Duplicate client names are not detectable via a query parameter — fetch and normalize names client-side (see references/examples.md).
Best Practices
- Standardize naming - Use consistent company name formats
- Verify before creating - Always search first to prevent duplicates
- Use classifications - Categorize clients for reporting
- Track account managers - Assign for accountability
- Keep contacts current - Deactivate departed employees
- Document relationships - Use notes for key account information
- Set up hierarchy correctly - Proper parent-child for billing
Related Skills
- HaloPSA Tickets - Service tickets for clients
- HaloPSA Contracts - Service agreements
- HaloPSA Assets - Client assets
- HaloPSA API Patterns - Authentication and queries