API Documentation.
Integrate matter plans, their field sets and the court, council and agency forms they use directly into your practice-management system. Pull a plan with its documents in one call, fill templates against the canonical matter.* vocabulary, and assemble everything locally.
https://www.openmatterplans.com/api/v1Authentication
Four access modes. Registry and template metadata are open; PMS integrations send an API key, and full plan bodies need a per-account one; community contributions use a browser session. Keyed endpoints fail closed in production.
Registry and template metadata. No credentials.
/councils, /forms/:id/latest, /templates, /templates/:id, /matter-types (teaser)PMS integration. A per-account key, or the transitional shared key.
/matter-plans, /matter-plans/:id/latest, /forms/:id/download, /councils/:id/report, /field-sets/*, /pms-fieldsFull plan bodies. A per-account key only: every call is logged to your account and counts towards a daily cap of 2,000.
/matter-plans/:id/download, /matter-plans/:id/kitWebsite sign-in. Create and revoke keys under Profile → API Access; verified practitioners suggest and vote.
/users/api-keys, /suggestions, /votes, /matter-plans/:idcurl "https://www.openmatterplans.com/api/v1/field-sets/resolve?practiceArea=conveyancing&jurisdiction=AU-QLD" \
-H "x-omn-api-key: omn_live_xxxxxxxxxxxxxxxx"
# or, equivalently:
-H "Authorization: Bearer omn_live_xxxxxxxxxxxxxxxx"Endpoints
Endpoints
/api/v1/matter-plans
The plan catalogue, one summary per plan (forks included). Send your key as x-omn-api-key; a signed-in browser session gets the same envelope. Each row carries contentHash and fieldSetSlug for cheap diffing, plus the canonical jurisdiction, practiceAreaKey and partyRole codes. Filters: page, limit (<=100), jurisdiction (AU-QLD), practiceAreaKey (conveyancing), practiceArea (website category, e.g. property), saliAreaOfLaw, countryCode, jurisdictionSub, search, updatedSince (ISO).
// Response Body
GET /api/v1/matter-plans?jurisdiction=AU-QLD&practiceAreaKey=conveyancing
{
"planSchemaVersion": 1,
"total": 2, "page": 1, "limit": 20, "pages": 1,
"data": [
{
"id": "94169c3a-a04c-4304-bedb-454bf212ba6d",
"slug": "au/qld/property/property-purchase-buyer/standard-residential-purchase",
"title": "Property Purchase (Buyer)",
"forkLabel": "QLD - Standard Residential Purchase",
"forkedFromId": null, "forkCount": 0,
"saliAreaOfLaw": "Real Estate", "saliProcess": "TRANSACTIONAL",
"practiceArea": "property", "category": "property",
"practiceAreaKey": "conveyancing",
"partyRole": "BUYER",
"countryCode": "AU", "jurisdictionSub": "QLD", "jurisdiction": "AU-QLD",
"documentLinkCount": 60,
"contentHash": "b2ad8ecdaa11...",
"planSchemaVersion": 1,
"updatedAt": "2026-10-14T06:38:51.605Z",
"fieldSetSlug": "plan-property_purchase-buyer-94169c3a",
"fieldsNormalized": true,
"netVotes": 0
}
]
}Matter field vocabulary
Templates fill against canonical matter.* tokens that resolve on your side, against your own matter data (matter data never leaves the PMS). Parties are addressed by role (matter.party.purchaser.fullName), never by position. Field sets form a hierarchy of up to five levels, base > area core > country > state > plan; resolve the one for a matter by context rather than hard-coding a token list.
GET /api/v1/field-sets/resolve?practiceArea=conveyancing&jurisdiction=AU-QLD{ "token": "matter.ourFirmName" }Fill from one canonical token, resolved against your own matter data.{ "token": "matter.fieldValues.settlement_date", "format": "DD/MM/YYYY" }Fill a value, formatted. DD/MM/YYYY is the only format in v1.{ "token": "matter.fieldValues.settlement_date", "part": "DD" }Fill one component of a value a form splits across boxes: DD / MM / YYYY, address parts (unitAndStreetNo, suburb, postcode ...), parcel parts (lot, planNo ...). Not implemented yet? Leave the field blank, never the whole value.{ "compose": ["matter.party.purchaser.email", "matter.party.purchaser.address"], "separator": "\n" }Fill one field from several tokens: drop the empty ones and join the rest with the separator (a new line by default).{ "constant": "Search request" }Literal text, the same on every assembly.{ "constant": true }On a checkbox: tick it unconditionally.{ "rule": "checkIf", "expression": "matter.matterType == 'conveyancing_purchase'" }Tick only when the expression is true (== / != against a single-quoted value).{ "ai": "the searched property’s nearest cross street" }No exact token: your PMS fills it with AI from its own matter context. Not supported yet? Leave it blank.{ "image": "matter.user.signature", "fit": "contain" }Draw an image your PMS holds (the operator’s signature PNG) into the field’s rectangle. The image never leaves the PMS.{ "signature": true }Prompt the signer to draw a signature at assembly and stamp it into the field.A pdf_form template embeds manifest.json (under /Names → /EmbeddedFiles); a docx_precedent carries the same JSON as the omn/manifest.json part and {placeholder} tags in the body. Each field maps to one rule above, and may also carry label, suggest and describe hints. A rule your engine does not know yet is a no-op: leave the field blank, never error.
Streaming matter plans into your PMS
Plans evolve as practitioners refine them. Rather than re-pull every plan, track freshness off the contentHash and only download what changed. Each plan is bound to a resolved field set from the Matter Field Standard, and every form it uses is filled from that set, so the tokens a PMS pre-fills against travel with the plan.
Find the plan
GET /api/v1/matter-plans (key), filtered by jurisdiction and practiceAreaKey. Store each plan’s id, contentHash and fieldSetSlug. Page with updatedSince to poll cheaply.
Take the kit
GET /api/v1/matter-plans/:id/kit (per-account key): the plan, its resolved field set and every document it uses, with field coverage. Or /download, plus GET /templates/:id for each document.
Stay fresh
GET /api/v1/matter-plans/:id/latest. A matching contentHash means you are current. A changed one: take the kit again (send If-None-Match) and re-read the stage and task ids.
Tasks carry dates, fields and documents
Each task names the field that holds its anchor date (baseKeyToken), the matter.* tokens it touches (pmsFieldRefs) and the templates it uses (documents). Your PMS turns those into the task card: a due date computed from the matter, the input to fill right on the card, and the forms to open, without leaving the checklist.
{
"id": "a862cc54-b90f-451a-bca3-341bc4e0ff51",
"title": "Open or Join the Electronic Workspace and Prepare the Transfer",
"relativeDays": -14,
"baseKeyDate": "Settlement Date",
"baseKeyToken": "matter.fieldValues.settlement_date",
"pmsFieldRefs": ["matter.fieldValues.elno_workspace_id",
"matter.fieldValues.settlement_date", "..."],
"documents": [ { "templateId": "24b2d696-9873-436f-bdaf-fc59334122d8",
"formName": "Transfer (Form 1)", "formNumber": "Form 1",
"templateType": "docx_precedent", "via": "own",
"downloadUrl": "..." } ]
}
// -> due date = the matter's settlement_date minus 14 days;
// inputs for the workspace id and settlement date on the card,
// typed from the field set (settlement_date: dataType "date", format "DD/MM/YYYY");
// the Transfer one click away, filled from the same set.planSchemaVersion, and the kit adds kitSchemaVersion. Both are 1 today. Gate your parser on them: if a response reports a higher version than your client understands, skip the plan and prompt for an update rather than mis-reading a changed shape. New keys are additive and never move a version, so ignore keys you do not recognise./api, and 2,000 plan bodies (/download and /kit) per key in any rolling 24 hours; both answer 429 with Retry-After. /councils, /templates, /field-sets/:slug, /download and /kit send an ETag: send If-None-Match and an unchanged resource costs a 304 (on /download and /kit it still counts towards the cap). Errors are { "error": "..." } on the original endpoints and { "error": { "code", "message" } } on the newer ones; read both.