Create the integration
A firm admin creates an API integration in Firm -> Apps & API access and chooses the least scopes required.
Developer docs
Use firm-owned API integrations to create cases, add parties, and send onboarding invites from another system with auditable, least-privilege access.
AI-ready reference
Stable URLs, schemas, examples, and guardrails.
Quickstart
The integration flow is intentionally small: create credentials, request a scoped token, then call only the endpoints enabled by the firm.
A firm admin creates an API integration in Firm -> Apps & API access and chooses the least scopes required.
Use the returned appId as clientId and store the one-time clientSecret in a backend secret manager.
Exchange client credentials for a short-lived MicroApp system token.
Create cases, add parties, and send invites with Authorization: Bearer <accessToken>.
Browser proxy
/api/v1
Local API
http://localhost:8081/v1
Production
Use relative /api/v1 from browser contexts
Authentication
Secrets never belong in browser code. This is a POST-only server-side call: exchange credentials from your backend for a MicroApp system token, then send the bearer token with each scoped API call.
curl -X POST "$VERIFY_CLIENT_BASE_URL/v1/microapps/system-tokens" \
-H "Content-Type: application/json" \
-d '{
"clientId": "00000000-0000-0000-0000-000000000000",
"clientSecret": "$VERIFY_CLIENT_CLIENT_SECRET",
"scopes": ["cases.create"],
"expiresInSeconds": 3600
}'curl -X POST "$VERIFY_CLIENT_BASE_URL/v1/cases" \
-H "Authorization: Bearer $VERIFY_CLIENT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"matterRef": "MAT-2026-001",
"matterType": "Purchase",
"parties": [
{
"name": "Alex Client",
"email": "alex@example.com",
"role": "Buyer"
}
]
}'The clientSecret is shown only when created or rotated.
Requested scopes are intersected with firm-enabled scopes.
allowedIpRanges are enforced at token issuance and API use.
Endpoint reference
These are the endpoints currently documented for server-to-server onboarding. Do not invent endpoints; inspect implementation before using anything outside this list.
Exchanges an API integration clientId and clientSecret for a scoped JWT.
{
"clientId": "00000000-0000-0000-0000-000000000000",
"clientSecret": "stored-secret",
"scopes": ["cases.create"],
"expiresInSeconds": 3600
}{
"ok": true,
"accessToken": "<jwt>",
"principal": {
"principalType": "microApp",
"tokenKind": "system",
"appId": "00000000-0000-0000-0000-000000000000",
"orgId": "org_123",
"identifier": "case-management-system",
"scopes": ["cases.create"]
},
"expiresAt": 1770000000
}Creates an onboarding matter and can include initial parties in the same request.
{
"matterRef": "MAT-2026-001",
"matterType": "Purchase",
"propertyAddress": {
"line1": "1 High Street",
"city": "London",
"postcode": "SW1A 1AA"
},
"requireSof": true,
"parties": [
{
"name": "Alex Client",
"email": "alex@example.com",
"mobile": "+447700900123",
"role": "Buyer",
"partyType": "individual",
"isPrimaryContact": true
}
]
}{
"caseId": "case_opaque_id",
"status": "NotStarted",
"parties": [
{
"partyId": "party_opaque_id",
"name": "Alex Client",
"clientAccessStatus": "not_sent"
}
]
}Returns paginated opaque case IDs for remote ledger sync and duplicate-check connectivity.
GET /v1/microapps/api/cases/ids?limit=200&cursor=<nextCursor>
Authorization: Bearer <system-token>{
"ok": true,
"items": ["case_opaque_id"],
"nextCursor": null
}Adds an individual or company party to an existing case.
{
"name": "Jordan Client",
"email": "jordan@example.com",
"mobile": "+447700900456",
"role": "Seller",
"partyType": "individual"
}{
"partyId": "party_opaque_id",
"name": "Jordan Client",
"email": "jordan@example.com",
"role": "Seller",
"clientAccessStatus": "not_sent"
}Sends a client onboarding invite by email or SMS according to party details.
{
"partyId": "party_opaque_id",
"sendSms": false
}{
"ok": true,
"inviteId": "invite_opaque_id",
"channel": "email"
}Duplicate safeguards
Use a stable source-system matterRef for every case. Verify Client rejects duplicate matter references within the firm, and integrations should keep a local ledger plus a remote sync check where required.
Scopes and schemas
Use the smallest scope set possible. Treat all identifiers as opaque strings and persist only the IDs needed to continue a workflow.
| Scope | Purpose | Endpoint |
|---|---|---|
| cases.create | Create onboarding cases | POST /v1/cases |
| parties.manage | Add parties to a case | POST /v1/cases/{caseId}/parties |
| invites.send | Send onboarding invites | POST /v1/cases/{caseId}/invites |
| cases.ids.list | List case IDs | GET /v1/microapps/api/cases/ids |
| users.list | List firm users | GET /v1/microapps/api/users |
Errors and audit
Integrations should branch on HTTP status first. Error body fields are useful but should be treated as optional.
Case, party, and invite actions performed by system tokens are written as MicroApp audit actors with the integration appId and identifier.
{
"actorType": "microApp",
"actorId": "<appId>",
"meta": {
"actorTokenKind": "system",
"actorIdentifier": "<identifier>"
}
}AI files
AI coding tools should start with llms.txt, then use the OpenAPI slice for schemas. Humans can use the same files to verify what automation is supported.
Short AI entrypoint with source files, scopes, URLs, and guardrails.
Machine-readable endpoint, request, and response schemas.
Firm admins manage integrations from Apps & API access.