Authenticate with a machine-to-machine client

Create an integration application, exchange its client credentials for an OAuth 2.0 access token, and call the API with it

The Cases API is secured with OAuth 2.0. Every endpoint that touches case or company data requires a bearer access token, and a server-side integration gets one using the client credentials grant — a machine-to-machine (M2M) flow, with no user sitting in front of a browser.

There are three steps: create an application, exchange its credentials for a token, and send that token on every request.

Step 1 — Create an application

Client credentials are issued from the Exizent platform, not from this API.

  1. Sign in to Exizent and open Company → Integrations (legal.exizent.com/case-management/company/integrations).
  2. Create a new application with the type Other.
  3. Give it a name that identifies the system connecting — the name appears in support conversations and audit trails, so "Practice Management Sync" beats "Test 1".
  4. Save. The Client ID and Client Secret are now shown on the application.

The client secret is a credential with the same reach as the integration itself. Store it in a secret manager or an environment variable, never in source control, and never ship it to a browser or mobile app — the client credentials grant is for server-side use only.

You will need a separate application for Sandbox and for Production. Credentials are not shared between environments.

If your firm's plan does not show the Integrations screen, or you need credentials issued another way, contact [email protected].

Step 2 — Exchange the credentials for an access token

POST to the /oauth/token endpoint of the identity server for your environment.

Authentication base URLs

EnvironmentIdentity base URL
Sandboxhttps://identity.testing.exizent.com
Productionhttps://identity.production.exizent.com

The request

curl --request POST \
  --url https://identity.testing.exizent.com/oauth/token \
  --header 'Content-Type: application/json' \
  --data '{
    "client_id": "{{your_client_id}}",
    "client_secret": "{{your_client_secret}}",
    "grant_type": "client_credentials",
    "audience": "https://resources.exizent.com",
    "scope": "read:case create:case update:case delete:case"
  }'
FieldValue
client_idFrom your integration application
client_secretFrom your integration application
grant_typeAlways client_credentials
audienceAlways https://resources.exizent.com — this is what tells the identity server the token is for the Cases API
scopeA space-separated list of the permissions you need (see below)

The response

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImRHYkhJYWxBUXZ4NU5ZS3h5Nz...",
  "scope": "read:case create:case update:case delete:case",
  "expires_in": 86400,
  "token_type": "Bearer"
}

Check the scope that comes back. The identity server grants the intersection of what you asked for and what your application is authorised to hold, so a scope you requested may simply be absent — which will show up later as a 403 rather than an error here.

Step 3 — Call the API

Put the token in an Authorization header on every request:

curl --request GET \
  --url https://cases.api.testing.exizent.com/cases \
  --header 'Authorization: Bearer {{access_token}}'
Authorization: Bearer {{access_token}}

That is the whole of it — there is no session, no cookie and nothing else to send.

Scopes

Scopes decide which endpoints a token may reach. Request only what your integration genuinely needs.

ScopeGrants
read:caseRead cases and everything on them — the deceased, people, estate items, documents
create:caseCreate new cases
update:caseChange a case and anything on it: the deceased, people, organisations, trusts, estate items, expenses, distributions, settings, status and owner
delete:caseDelete case data
read:companyRead company details
update:companyChange company settings
delete:companyDelete company data

Mapping the endpoints in these guides to the scope each one needs:

EndpointScope
GET /cases, GET /cases/{id}read:case
POST /casescreate:case
PUT /cases/{id}/deceasedupdate:case
POST /cases/{caseId}/peopleupdate:case
PUT /cases/{caseId}/people/{personId}update:case

Note that adding a person is an update to the case, not a case creation — it needs update:case, not create:case. That is true of everything that hangs off a case.

Roles

Scope alone is not always enough. The endpoints that change a case also require the token to carry one of the platform roles — CompanyOwner, Administrator, CaseOwner or Delegate — which is configured against your integration application when it is created.

In practice this is transparent: an application created through the Integrations screen arrives with what it needs. But it explains a particular failure. If a request returns 403 even though the token clearly carries update:case, the missing piece is the role, not the scope. Contact [email protected] with the application name and they can check how it was provisioned.

Token lifetime and caching

Tokens are short-lived by design, and the identity server tells you how long yours lasts: read expires_in from the token response — it is a number of seconds — rather than assuming a fixed lifetime, because the value differs between environments and can change.

Fetch a token once, cache it in memory, and reuse it until it is close to expiring. Refresh a little early — thirty to sixty seconds before expires_in elapses — so that a token does not lapse mid-flight between your check and the API receiving it.

Two habits to avoid:

  • Do not request a fresh token per API call. It is slow, and the identity server rate-limits aggressive clients.
  • Do not persist tokens to disk or to a shared cache that outlives the process. Re-requesting from the credentials is cheap; a leaked token is not.

There is no refresh token in the client credentials grant. When the token expires, you simply request another one the same way.

Troubleshooting

SymptomLikely cause
401 UnauthorizedNo Authorization header, a malformed one (the Bearer prefix is required), or an expired token
401 with a freshly issued tokenThe token was minted for the wrong environment — a Sandbox token will not open Production, or vice versa
403 ForbiddenThe token is genuine but lacks the scope the endpoint requires, or the required role — check the scope on the token response first
403 on every endpointaudience was omitted or wrong on the token request, so the token was not issued for the Cases API
404 on a case you know existsThe token belongs to a different company. Cases are only ever visible to the company that owns them
429 from the identity serverToo many token requests — cache the token as described above

Next

With a token in hand, work through Manage the deceased and people on a case.


Did this page help you?