Concurrency
What stops two updates to the same resource from silently losing one of them.
The problem
Two operators open the same issuer. One changes the display name, the other changes the status mechanism. Both save. Without concurrency control, whoever saved second wins entirely, and the first change is gone with nothing reporting it.
How the Management API handles it
A read returns an entity tag:
GET /management/issuers/workforce?api-version=2026-08-30
HTTP/1.1 200 OK
ETag: "AAAAAAAAB9E="
Quote it on the update:
PATCH /management/issuers/workforce?api-version=2026-08-30
If-Match: "AAAAAAAAB9E="
If the resource has changed since you read it, the tag no longer matches and the update is rejected:
HTTP/1.1 412 Precondition Failed
{ "error": { "code": "precondition_failed", "message": "Issuer 'workforce' has changed since the entity tag you supplied. Re-read it and retry." } }
The write does not happen. A 412 that still applied the change would be worse than no concurrency control, because you would believe you were protected.
Omitting If-Match
An update with no If-Match is unconditional and succeeds. That is the standard HTTP reading, and it keeps the
operation usable for the many callers writing a value nobody else touches.
DiligenceID does not return 428 Precondition Required. Requiring If-Match everywhere would break every
existing integration to provide a guarantee most of them do not need. Where a resource genuinely cannot
tolerate a blind write, that is a decision for the resource, not for the whole plane.
If your own workflow needs the guarantee, always send If-Match. Nothing stops you.
If-Match: * means "only if it exists", which is already true by the time the check runs.
409 and 412 are different
| Status | Meaning | What to do |
|---|---|---|
409 Conflict |
The request cannot be reconciled with the resource's state | Do not retry unchanged. Something is genuinely wrong |
412 Precondition Failed |
Your copy is out of date | Re-read, re-apply, retry |
Collapsing them would tell a caller to give up when they should retry.
Which resources have entity tags
| Resource | ETag |
|---|---|
| Issuer | Yes — and If-Match is honoured on update |
| Organisation | Yes |
| Credential configuration | No |
| Verification policy | No |
Verification policies carry no version token in storage, so no entity tag is emitted. One derived from a timestamp would be a concurrency guarantee the storage layer does not actually make. Suspend and reactivate are state transitions rather than blind writes, so the absence costs little.
The compatibility routes
/v1.0 and /v1 keep the older mechanism: send rowVersion in the request body, and a stale value returns
409.
Those routes deliberately ignore If-Match. A caller there may be sending it through a proxy or a generic
client library, and honouring it would change behaviour under an integration that never opted in.
The canonical plane hides rowVersion behind the entity tag, because which storage column backs the version is
not something an integrator should need to know.