Available lang sa Ingles ang dokumentasyon ng produkto.
Matter types endpoints
A matter type is a sub-type within a practice area, such as Divorce or Custody under Family law. These endpoints list, create, read, rename, and delete them.
All paths sit under the base address https://api.esqase.com, and every request needs an API key. See Authentication and scopes if you have not made your first call yet.
The endpoints
| Action | Method and path | Scope needed |
|---|---|---|
| List | GET /v1/matter-types?practiceAreaId={id} | matter-types:read |
| Create | POST /v1/matter-types | matter-types:write |
| Retrieve | GET /v1/matter-types/{id} | matter-types:read |
| Update | PATCH /v1/matter-types/{id} | matter-types:write |
| Delete | DELETE /v1/matter-types/{id} | matter-types:write |
The matter type object
id: the id Esqase assigns.practiceAreaId: the practice area this type belongs to. Every matter type belongs to exactly one.name: the type's name.status: its lifecycle state. Matter types created through the API start asACTIVE.createdAt,updatedAt: timestamps, ornullon the create response.
List matter types
GET /v1/matter-types returns the types under one practice area. The practiceAreaId query parameter is required, because matter types are always scoped to a practice area. Omit it and you get 400 with the code invalid_request.
Two more query parameters control the page:
limit: how many records to return. Minimum 1, maximum 100, default 20.offset: how many records to skip before the page starts. Minimum 0, default 0.
curl "https://api.esqase.com/v1/matter-types?practiceAreaId=b2c3d4e5-1000-4a1b-9c2d-1234567890ab&limit=20" \
-H "Authorization: Bearer $ESQASE_API_KEY"
{
"data": [
{
"id": "e5f6a7b8-0001-4a1b-9c2d-1234567890ab",
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Divorce",
"status": "ACTIVE",
"createdAt": "2026-07-01T09:20:00.000Z",
"updatedAt": "2026-07-01T09:20:00.000Z"
},
{
"id": "e5f6a7b8-0002-4a1b-9c2d-1234567890ab",
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Custody",
"status": "ACTIVE",
"createdAt": "2026-07-01T09:21:00.000Z",
"updatedAt": "2026-07-01T09:21:00.000Z"
}
],
"pagination": { "limit": 20, "offset": 0, "total": 2 }
}
Tip: Retrieving a practice area (GET /v1/practice-areas/{id}) also returns its matterTypes, each with an id and a name. Use this endpoint when you want the full records with their status and timestamps, or when you need to page through a long list.
Create a matter type
POST /v1/matter-types creates one matter type and returns 201 Created. It takes two fields:
practiceAreaId(required): the practice area the type belongs to.name(required): 1 to 64 characters.
curl -X POST https://api.esqase.com/v1/matter-types \
-H "Authorization: Bearer $ESQASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Divorce"
}'
{
"data": {
"id": "e5f6a7b8-0001-4a1b-9c2d-1234567890ab",
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Divorce",
"status": "ACTIVE",
"createdAt": null,
"updatedAt": null
}
}
Note: The create response echoes what was written, so createdAt and updatedAt come back as null. Retrieve the matter type by id if you need its real timestamps.
Retrieve a matter type
GET /v1/matter-types/{id} returns one matter type, including the id of the practice area it belongs to.
curl https://api.esqase.com/v1/matter-types/e5f6a7b8-0001-4a1b-9c2d-1234567890ab \
-H "Authorization: Bearer $ESQASE_API_KEY"
{
"data": {
"id": "e5f6a7b8-0001-4a1b-9c2d-1234567890ab",
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Divorce",
"status": "ACTIVE",
"createdAt": "2026-07-01T09:20:00.000Z",
"updatedAt": "2026-07-01T09:20:00.000Z"
}
}
If no matter type in your firm has that id, or it has been deleted, you get 404 with the code not_found.
Update a matter type
PATCH /v1/matter-types/{id} renames the matter type. Renaming is the only change the API supports here, and a matter type cannot be moved to a different practice area.
name(required): 1 to 64 characters.
curl -X PATCH https://api.esqase.com/v1/matter-types/e5f6a7b8-0001-4a1b-9c2d-1234567890ab \
-H "Authorization: Bearer $ESQASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Dissolution" }'
{
"data": {
"id": "e5f6a7b8-0001-4a1b-9c2d-1234567890ab",
"practiceAreaId": "b2c3d4e5-1000-4a1b-9c2d-1234567890ab",
"name": "Dissolution",
"status": "ACTIVE",
"createdAt": "2026-07-01T09:20:00.000Z",
"updatedAt": "2026-07-02T13:40:00.000Z"
}
}
Delete a matter type
DELETE /v1/matter-types/{id} is a soft delete: the matter type is archived out of the active lists rather than erased.
curl -X DELETE https://api.esqase.com/v1/matter-types/e5f6a7b8-0001-4a1b-9c2d-1234567890ab \
-H "Authorization: Bearer $ESQASE_API_KEY"
{
"data": {
"id": "e5f6a7b8-0001-4a1b-9c2d-1234567890ab",
"deleted": true
}
}
Full examples in JavaScript and Python
Both examples read the key from an environment variable and make sure a set of matter types exists under one practice area, creating only the missing ones.
JavaScript (fetch)
const BASE = "https://api.esqase.com/v1";
const headers = {
Authorization: `Bearer ${process.env.ESQASE_API_KEY}`,
"Content-Type": "application/json",
};
const practiceAreaId = "b2c3d4e5-1000-4a1b-9c2d-1234567890ab";
const wanted = ["Divorce", "Custody", "Adoption"];
const listResponse = await fetch(
`${BASE}/matter-types?practiceAreaId=${practiceAreaId}&limit=100`,
{ headers },
);
const { data: existing } = await listResponse.json();
const existingNames = new Set(existing.map((row) => row.name));
for (const name of wanted) {
if (existingNames.has(name)) continue;
const createResponse = await fetch(`${BASE}/matter-types`, {
method: "POST",
headers,
body: JSON.stringify({ practiceAreaId, name }),
});
const { data: matterType } = await createResponse.json();
console.log(`Created ${matterType.name} (${matterType.id})`);
}
Python (requests)
import os
import requests
BASE = "https://api.esqase.com/v1"
headers = {
"Authorization": f"Bearer {os.environ['ESQASE_API_KEY']}",
"Content-Type": "application/json",
}
practice_area_id = "b2c3d4e5-1000-4a1b-9c2d-1234567890ab"
wanted = ["Divorce", "Custody", "Adoption"]
existing = requests.get(
f"{BASE}/matter-types",
headers=headers,
params={"practiceAreaId": practice_area_id, "limit": 100},
).json()["data"]
existing_names = {row["name"] for row in existing}
for name in wanted:
if name in existing_names:
continue
matter_type = requests.post(
f"{BASE}/matter-types",
headers=headers,
json={"practiceAreaId": practice_area_id, "name": name},
).json()["data"]
print(f"Created {matter_type['name']} ({matter_type['id']})")
Errors
| Status | Code | When |
|---|---|---|
| 400 | invalid_request | The practiceAreaId query parameter is missing on the list call, or name is missing, empty, or longer than 64 characters. |
| 401 | unauthorized | The key is missing, wrong, revoked, or expired. |
| 403 | forbidden | The key is missing matter-types:read or matter-types:write, or the member who created it lacks the firm's Practice areas permission. |
| 404 | not_found | No matter type in your firm has that id, or it has been deleted. |
| 429 | rate_limited | Too many requests. Wait the Retry-After seconds. |
The full list of status codes is in Authentication and scopes.
Note: Practice areas and matter types share one firm permission. A key needs the matching matter-types:* scope, and the member who created it needs the firm's Practice areas permission, which covers matter types too. See Authentication and scopes.
Common questions
- Why does listing need
practiceAreaId? Matter types only exist inside a practice area, so there is no firm-wide list. Call the endpoint once per practice area. - Can I move a matter type to another practice area? No. Create it under the right practice area, and delete the one in the wrong place.
- Can I attach a matter type to a matter through the API? No. The matters endpoints do not take a matter type today. Set it in the dashboard.
- Do I need a separate scope from practice areas? Yes.
practice-areas:*andmatter-types:*are separate scopes, even though they share the same firm permission.