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
}

Try this endpoint →

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"

Try this endpoint →

POST/api/v1/matters

Opens a matter under an existing client in your firm.

Module: matters

  • title (required) — Matter title
  • clientId (required) — Client id in your firm
  • description — Optional
  • status — Optional. Default OPEN
  • stage — Optional. Default INTAKE
  • priority — Optional. Default MEDIUM
  • practiceArea — Optional
  • deadline — Optional. ISO date
  • counterparty — 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/matters

Fires webhook matter.created.

Try this endpoint →

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"

Try this endpoint →

POST/api/v1/clients

Creates a client in the firm attached to the API key.

Module: clients

  • name (required) — Client name
  • type (required) — INDIVIDUAL or CORPORATE
  • email — Optional
  • phone — Optional
  • address — Optional
  • referralSource — 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/clients

Fires webhook client.created.

Try this endpoint →

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"

Try this endpoint →

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 firm
  • userId (required) — Staff member id
  • hours (required) — Hours worked
  • rate — Optional. Default 0
  • currency — Optional. Default USD
  • date — Optional. ISO date. Default today
  • description — 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-entries

Try this endpoint →

Staff

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"

Try this endpoint →

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 created
  • matter.stage_changed — A matter stage changes
  • invoice.created — An invoice is created
  • invoice.paid — An invoice is marked paid
  • lead.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.