Practa API
REST documentation for firm-scoped integrations — matters, clients, time, and staff.
Introduction
The PractaHQ REST API lets your firm connect practice data to other systems — case management exports, time capture, client onboarding, and internal tools.
All v1 endpoints are scoped to your firm. A request never sees another firm's clients, matters, or staff. Generate a key under Firm Settings → API keys. Keys start with phq_.
Base URL: https://practahq.co.zw
Keep keys server-side in your own apps. Do not embed them in public websites or mobile binaries.
Authentication
Every request needs a Bearer token. Missing or revoked keys return 401. A plan without API Access, or an inactive firm, returns 403.
Authorization: Bearer phq_your_api_key_here
Required Modules
Each endpoint checks a module on your plan:
api_access— required for every key. Also gates stats.matters— matters list and create.clients— clients list and create.billing— time entries list and create.hrm— staff list.
Errors & Limits
Documented as 1,000 requests per hour per API key. Over the limit you receive 429.
400— Validation failed (missing or invalid body field).401— Missing or invalid API key.403— Module not on your plan, or firm subscription inactive.404— Resource not in your firm.429— Rate limit exceeded.500— Unexpected server error.
Stats
Firm-wide totals for staff, clients, matters, and billed versus unbilled time value.
Revenue figures are hours × rate from time entries, rounded to whole currency units. Requires the api_access module, which every API key already needs.
GET/api/v1/stats
Returns counts and billed/unbilled time value for the firm attached to the API key.
Module: api_access
Request
curl -H "Authorization: Bearer phq_..." "https://practahq.co.zw/api/v1/stats"
Example response
{
"userCount": 8,
"clientCount": 42,
"matterCount": 110,
"openMatters": 37,
"totalRevenue": 18500,
"unbilledRevenue": 4200
}Matters
List and open matters for your firm, with client and assigned lawyer.
Creating a matter requires an existing client in the same firm. Fires webhook matter.created. Requires the matters module.
GET/api/v1/matters
Lists matters for your firm, newest first, including client name and assigned lawyer.
Module: matters
status— Optional. OPEN, PENDING, or CLOSED.
Request
curl -H "Authorization: Bearer phq_..." "https://practahq.co.zw/api/v1/matters?status=OPEN"
POST/api/v1/matters
Opens a matter under an existing client in your firm.
Module: matters
title(required) — Matter titleclientId(required) — Client id in your firmdescription— Optionalstatus— Optional. Default OPENstage— Optional. Default INTAKEpriority— Optional. Default MEDIUMpracticeArea— Optionaldeadline— Optional. ISO datecounterparty— Optional
Request
curl -X POST -H "Authorization: Bearer phq_..." -H "Content-Type: application/json" \
-d '{ "title": "Smith vs Jones", "clientId": 12 }' \
https://practahq.co.zw/api/v1/mattersFires webhook matter.created.
Clients
List and create clients for your firm.
Creating a client fires webhook client.created. Requires the clients module.
GET/api/v1/clients
Lists clients for your firm, newest first.
Module: clients
Request
curl -H "Authorization: Bearer phq_..." "https://practahq.co.zw/api/v1/clients"
POST/api/v1/clients
Creates a client in the firm attached to the API key.
Module: clients
name(required) — Client nametype(required) — INDIVIDUAL or CORPORATEemail— Optionalphone— Optionaladdress— OptionalreferralSource— Optional
Request
curl -X POST -H "Authorization: Bearer phq_..." -H "Content-Type: application/json" \
-d '{ "name": "Acme Corp", "type": "CORPORATE" }' \
https://practahq.co.zw/api/v1/clientsFires webhook client.created.
Time entries
List billed and unbilled time, or log hours against a matter.
Each row includes the matter title and the fee earner name. Logging time requires a matter and staff member in your firm. Requires the billing module.
GET/api/v1/time-entries
Lists time entries for your firm's staff.
Module: billing
billed— Optional. true or false.
Request
curl -H "Authorization: Bearer phq_..." "https://practahq.co.zw/api/v1/time-entries?billed=false"
POST/api/v1/time-entries
Logs time against a matter for a staff member in your firm.
Module: billing
matterId(required) — Matter id in your firmuserId(required) — Staff member idhours(required) — Hours workedrate— Optional. Default 0currency— Optional. Default USDdate— Optional. ISO date. Default todaydescription— Optional
Request
curl -X POST -H "Authorization: Bearer phq_..." -H "Content-Type: application/json" \
-d '{ "matterId": 4, "userId": 2, "hours": 1.5, "rate": 150, "currency": "USD" }' \
https://practahq.co.zw/api/v1/time-entriesStaff
List fee earners and roles in your firm. Passwords are never returned.
Requires the hrm module.
GET/api/v1/staff
Returns id, name, email, role, position, department, and status for staff in your firm.
Module: hrm
Request
curl -H "Authorization: Bearer phq_..." "https://practahq.co.zw/api/v1/staff"
Webhooks
Register a URL in the app under Webhooks to receive signed HTTP POSTs instead of polling. Each delivery includes X-PractaHQ-Event (event name) and X-PractaHQ-Signature (HMAC-SHA256 hex digest of the raw body, using your webhook secret). Verify before you trust the payload.
client.created— A client is created (app or API)matter.created— A matter is createdmatter.stage_changed— A matter stage changesinvoice.created— An invoice is createdinvoice.paid— An invoice is marked paidlead.converted— A lead is converted to a client
Verify the signature
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
if (expected !== req.headers['x-practahq-signature']) throw new Error('Invalid signature')Test console
Send a real request from this page. Create an API key in PractaHQ, paste it below, pick an endpoint, and send. GET calls are safe to retry. POST calls create real records in the firm attached to that key.