Professional API: Getting Started
Read your own practice data (profile, appointments, approaches, matters and engagement letters) from your own systems, and create will drafts for your clients.
What the Professional API Is
A view of your practice data, and one write surface for will drafts, for your own systems.
Scope of the API
The Professional API lets your practice management software, CRM or internal dashboard read the data Orchard72 already holds for your practice. Every endpoint lives under /api/v1/pro/ext/ and returns JSON.
The read collections are read-only: they have no create, update or delete endpoints. The one write surface is will drafts for your own clients at /api/v1/pro/ext/wills/, which needs its own scope and a plan that includes it (see Creating Will Drafts below). Anything else that changes data is still done in the professional dashboard.
Who Can Use It
API access is part of the Pro Growth and Pro Enterprise plans. On Pro Free and Pro Starter the endpoints are present but refuse every request, because those plans include no API allowance.
Note
Authentication
Creating a key and sending it with every request.
Creating a Key
- Open the Developer section of your professional dashboard
- Create a key and give it a descriptive name, so you can tell your integrations apart later
- Choose the
pro:readscope for the read collections. If your plan includes will creation you can also includepro:wills:write. Scopes never imply one another, so a key needspro:readto read andpro:wills:writeto create will drafts - Copy the key straight away and store it in a secrets manager or environment variable
Important
Sending the Key
Professional keys carry the same twai_ prefix as consumer keys (older keys beginning pk_ keep working) and travel in the Authorization header using the Bearer scheme:
Authorization: Bearer twai_your_api_key_here
- A missing or malformed key returns
401 - A valid key without the scope an endpoint needs (
pro:read, orpro:wills:writefor will drafts) returns403 - A valid, correctly scoped key on a plan without API access also returns
403, rather than an upgrade prompt dressed up as a success
Your First Call
Confirm the key works before you build anything on it.
Fetch Your Profile
- Make a GET request to
/api/v1/pro/ext/me/with your key in theAuthorizationheader - A working key returns your professional profile. If the account has no professional profile attached, the response is a
404carrying{"detail": "No professional profile found for this account."} - A
401means the key is wrong, revoked or expired; a403means the key lackspro:reador the plan has no API access
Tip
/api/v1/pro/ext/me/ rather than a collection. It is the cheapest call that proves the key, the scope and the plan entitlement are all in order.The Read Collections
What the API exposes, and what it deliberately does not.
Endpoints
/api/v1/pro/ext/me/: your professional profile/api/v1/pro/ext/appointments/: list, plus a detail view per appointment/api/v1/pro/ext/approaches/: list, plus a detail view per approach/api/v1/pro/ext/matters/: list only. There is no bare matter detail endpoint; the matter brief is fetched from/api/v1/pro/ext/matters/{id}/brief//api/v1/pro/ext/engagement-letters/: list, plus a detail view per engagement letter
List responses are paginated, 100 records per page by default.
Matter Briefs Are Consent-Gated
A matter brief leaves the platform only while the client’s consent for that matter is live. The consent is re-checked on every single call, never cached, and each fetch is written to the matter’s disclosure log, recording the key prefix used but never the key itself.
Note
Creating Will Drafts
Create a will draft for one of your own clients, poll it, and retry safely.
Who Can Create Will Drafts
Will creation is part of the Pro Growth and Pro Enterprise plans (and the founding-member Pro Growth plan). It needs a key carrying the pro:wills:write scope, which the Developer section offers only while your plan includes will creation.
Pro Free and Pro Starter do not include will creation. The hourly will-draft budget for each plan is listed under Partner will creation in the Rate Limits section below.
That hourly budget applies on top of your ordinary plan allowance, and each draft also uses one will-generation credit from your plan; when the credits are used up, a create returns 402. Polling and cancelling use no credits. Your subscription record reports partner_will_api_enabled and partner_will_create_rate_limit_per_hour, so an integration can read its own entitlement.
Note
Endpoints
POST /api/v1/pro/ext/wills/: create a will draft and queue its generationGET /api/v1/pro/ext/wills/{id}/: one will you created, and its generation statusPOST /api/v1/pro/ext/wills/{id}/cancel/: stop a generation that has not finished
The Request
professional_client_id: the identifier of one of your own active clients. Any other identifier returns404client_reference(optional): your own reference for the will, up to 255 characterswill: an object of named sections.jurisdictionandtestatorare required;residence,family,assets,gifts,funeral,executorsandwitnessesare optional
Each section is checked against the same rules as the will interface in the dashboard, and the whole request is checked before anything is created, so a 400 means nothing was stored. An unknown field or section is a 400, never silently dropped: a refused section comes back under will, keyed by section name. Replace BASE_URL with the address you sign in at:
curl -X POST "BASE_URL/api/v1/pro/ext/wills/" \
-H "Authorization: Bearer twai_your_api_key_here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 7d3f9a52-client-4471-will-1" \
-d '{
"professional_client_id": "YOUR_CLIENT_ID",
"client_reference": "MATTER-4471",
"will": {
"jurisdiction": {
"will_country": "GB",
"will_state": "ENG",
"will_state_name": "England",
"jurisdiction": "GB-ENG",
"user_country": "GB",
"date_of_birth": "1970-05-14",
"will_type": "solo"
},
"testator": {
"first_name": "Harriet",
"last_name": "Blackwood"
}
}
}'The Response and Its Status
A create answers 202 with a Location header to poll and a body carrying identifiers and status only, never the client’s details or the will’s content:
{
"id": "3f2b6c1e-8d4a-4b7e-9c21-5a0e7d9f1b44",
"status": "pending",
"professional_client_id": "YOUR_CLIENT_ID",
"client_reference": "MATTER-4471",
"created_at": "2026-09-24T10:15:00Z",
"updated_at": "2026-09-24T10:15:00Z"
}status is one of pending, processing, completed, failed or cancelled. Poll GET /api/v1/pro/ext/wills/{id}/ to follow it. A failed generation is reported in status, not as an HTTP error; create a new draft to try again. Cancelling a will with nothing generating returns 400.
Retrying Safely With Idempotency-Key
- Every create must carry an
Idempotency-Keyheader, up to 255 characters and unique to that will; without one the request returns400 - Sending the same key and the same body again within 24 hours returns the will the first request created, with an
Idempotent-Replayed: trueheader, and does not create a second will - Reusing a key with a different body returns
422; use a new key for a new will - A refused request (
400,402,404or422) stores nothing, so you can correct it and send it again with the same key
Tip
Rate Limits
How much you may call, and where to read your own allowance.
Limits are counted on a sliding window. When you go over one, the API answers 429 Too Many Requests with a Retry-After header telling you how long to wait.
Professional API
Every request to /api/v1/pro/ext/.
- Pro Growth: 2,000 requests per hour
- Support Service Provider Growth: 2,000 requests per hour
- Pro Enterprise: unlimited
- Support Service Provider Enterprise: unlimited
- Founding Member Pro Growth: 2,000 requests per hour
Shared by every key you hold, so a new key never adds to it. Plans not listed here have no access to this API. Scopes: pro:read, pro:org:read, pro:wills:write.
Partner will creation
POST /api/v1/pro/ext/wills/ only, on top of the Professional API budget.
- Pro Growth: 30 requests per hour
- Pro Enterprise: 300 requests per hour
- Founding Member Pro Growth: 30 requests per hour
Shared by every key you hold, so a new key never adds to it. Plans not listed here have no access to this API. Scopes: pro:wills:write.
Matter briefs and will documents
GET /api/v1/pro/ext/matters/{id}/brief/, GET /api/v1/pro/ext/wills/{id}/document/ and one-off brief bundles, sharing one budget, on top of the Professional API budget.
- Every plan: 30 requests per hour
Shared by every key you hold, so a new key never adds to it. Scopes: pro:read.
Professional MCP agent tools
MCP tool calls, counted separately from your REST budget.
- Pro Growth: 2,000 requests per hour
- Support Service Provider Growth: 2,000 requests per hour
- Pro Enterprise: unlimited
- Support Service Provider Enterprise: unlimited
- Founding Member Pro Growth: 2,000 requests per hour
Shared by every key you hold, so a new key never adds to it. Plans not listed here have no access to this API. Scopes: pro:read, pro:org:read.
These figures come from the limits the API enforces, also served as JSON at /api/v1/portfolio/rate-limits/.
Seeing Your Own Limit
The Developer section of your professional dashboard shows the allowance your plan currently grants, the number of keys you may hold, and the scope your keys are issued with. The same figures come back on your subscription record as rate_limit_per_hour (an integer, or null where the plan is unlimited), so an integration can read its own ceiling rather than hard-coding one.
Tip
X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. The allowance is per user, shared by all of your keys, and a per-minute burst cap derived from your hourly rate stops it being spent in a few seconds; pace your calls from the headers and back off when you are told to.When You Exceed It
An over-limit request returns 429 with a Retry-After header and a body carrying error_code of RATE_LIMITED plus a wait_time in seconds. Honour whichever you read; do not retry immediately.
If you need to know about changes as they happen, subscribe to webhooks instead of polling.
Errors and Scoping
The response shapes to code against, and why a 404 is not always a missing record.
Error Shapes
Two shapes are in use on this surface, so handle both rather than assuming one:
- The scoping and profile refusals carry a
detailkey, for example{"detail": "Not found."} - Authentication, permission and throttling refusals carry
errorandstatus_code, and the429additionally carriesmessage,error_codeandwait_time
404 Rather Than 403
Asking for a record that belongs to another practice returns 404, not 403, and it is the identical body you get for an identifier that does not exist anywhere. The queryset behind each collection is filtered to your own practice before the lookup happens, so a record outside it is simply not there to be found.
This is deliberate. A 403 would confirm that the identifier exists and belongs to someone, which is exactly the signal an identifier-guessing attack needs. The matter brief goes further still: "not yours" and "consent is not live" return byte-identical responses, so the presence or absence of a client’s consent cannot be probed from outside.
Note
404 on an identifier you believe is yours, check the account the key belongs to before assuming the record was deleted.Related Topics
Can’t find what you’re looking for?
Our support team is here to help. Contact us and we’ll get back to you as soon as possible.
Contact Support
