Get Started with the API
Last updated: October 21, 2026
This walkthrough takes a developer from nothing to a working integration: a key, a first read, a first write, an update, and a batch. Each step builds on the one before, so follow them in order. The API is available on the Enterprise plan Enterprise , and an admin creates keys, so you either need to be an admin or ask one to follow the first step for you.
Before you start
The API lives under /api/v1 on your Lextree address. A subscription on the US cell uses https://us.lextree.ai, and a subscription on the EU cell uses https://eu.lextree.ai. The examples below use the US address, so change the host if your subscription is on the EU cell.
The examples work against the Boards record type, because it is small and every subscription with the Board Governance module has it. Any other record type behaves the same way. Replace the IDs in the examples with IDs from your own subscription.
Create a key
An admin opens the Subscription page from the avatar menu and finds API Access.
- Click Create API key.
- Enter a name that says which integration the key serves, such as “Board sync”.
- Choose a scope. The walkthrough writes records, so choose Read and write. That scope creates, updates, trashes and restores records, and it cannot permanently delete anything.
- Leave Configuration access off. It lets a key read and change how the subscription is set up, and nothing here needs it.
- Click Save, then copy the key.
Lextree shows the key once. If you lose it, revoke it and create another. A key’s scope can’t be changed after creation either, so to widen or narrow a key, create a new one and revoke the old one.
A key belongs to the subscription, not to a person. It reads across every enabled module and carries nobody’s individual permissions, so store it as you would an admin password.
Every request sends the key as a Bearer token. To keep the examples short, put it in an environment variable:
export LEXTREE_KEY="lt_live_ab12cd34_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
List the record types
Start by asking which record types your key can reach. The set depends on the modules your subscription has enabled, and the call also tells you the path to use for each record type:
curl "https://us.lextree.ai/api/v1/record_types" \
-H "Authorization: Bearer $LEXTREE_KEY"
{
"data": [
{
"record_type": "boards",
"label": "Board",
"description": "A board of directors that governs an organization.",
"nested_under": "organizations",
"module_key": "board_governance",
"is_reference": false,
"web_url_template": "https://us.lextree.ai/boards/{id}"
}
],
"has_more": false,
"next_cursor": null
}
The response above is trimmed to one entry; a subscription with every module enabled lists well over a hundred. Each entry’s record_type is the path segment you use from here on, so Boards live at /api/v1/boards. The nested_under value names the parent record type, and it is null for top-level record types. The web_url_template value is the address of a record’s page in the app, with {id} standing for a record’s ID, so you can fill it in to give a person a link. It is null for a record type with no page of its own.
To see which fields a record type has, which are writable and which are required, request its schema:
curl "https://us.lextree.ai/api/v1/boards/schema" \
-H "Authorization: Bearer $LEXTREE_KEY"
For Boards, the required fields are entity_id, the organization the board governs, and name.
Read records
List two boards:
curl "https://us.lextree.ai/api/v1/boards?limit=2" \
-H "Authorization: Bearer $LEXTREE_KEY"
Every list comes back in the same envelope:
{
"data": [
{
"id": "0e6d1a54b9c34f7e8a2150d7c3b46f19",
"name": "Compensation committee",
"entity_id": {
"id": "f0348da1bc614dc3bab5d1b3c0aa8d3c",
"name": null
},
"custom_fields": {
"board_type": "Directors",
"meeting_frequency": "Quarterly"
},
"timeline_status": "Active"
}
],
"has_more": true,
"next_cursor": "eyJydCI6ImJvYXJkcyIs…"
}
The response is trimmed to one board and a few custom fields. A record’s own fields sit at the top level, and its custom fields sit under custom_fields, keyed by each field’s api_name.
To read the next page, pass next_cursor back as the cursor parameter. Repeat until has_more is false:
curl "https://us.lextree.ai/api/v1/boards?limit=2&cursor=eyJydCI6ImJvYXJkcyIs…" \
-H "Authorization: Bearer $LEXTREE_KEY"
To read one record, put its ID in the path: GET /api/v1/boards/{id}. That call returns the bare record without the envelope.
Create a record
A write uses the same shape a read returns. Static fields go at the top level, and custom fields go under custom_fields. A reference field takes the ID of the record it points to.
Every create needs an Idempotency-Key header. Use any string that is unique to the operation; a UUID works well. If a request times out and you send it again with the same key, Lextree returns the stored response, marked Idempotent-Replayed: true, instead of creating a second board.
curl -X POST https://us.lextree.ai/api/v1/boards \
-H "Authorization: Bearer $LEXTREE_KEY" \
-H "Idempotency-Key: 7d2a9c40-3b1e-4f58-9a6c-e1b05d83f2a7" \
-H "Content-Type: application/json" \
-d '{
"name": "Technology committee",
"entity_id": "f0348da1bc614dc3bab5d1b3c0aa8d3c",
"custom_fields": {
"board_type": "Directors",
"standard_term": "3 years"
}
}'
Lextree answers 201 Created with the record as a GET would return it:
{
"id": "5ab3e7c9d2f14860b7194e0a6c83d5f2",
"name": "Technology committee",
"entity_id": {
"id": "f0348da1bc614dc3bab5d1b3c0aa8d3c",
"name": null
},
"custom_fields": {
"board_type": "Directors",
"standard_term": "3 years"
},
"updated_by_api_key": {
"id": "49371827bbb847e0b1457a053f415052",
"name": "Board sync"
}
}
The response is trimmed to the fields that matter here. The updated_by_api_key value shows that the change is attributed to your key. The same attribution appears in the app’s audit history.
Update a record
Use PATCH and send only the fields you want to change. Sending null clears a field:
curl -X PATCH https://us.lextree.ai/api/v1/boards/5ab3e7c9d2f14860b7194e0a6c83d5f2 \
-H "Authorization: Bearer $LEXTREE_KEY" \
-H "Content-Type: application/json" \
-d '{
"custom_fields": {
"authorized_seats": 5,
"standard_term": null
}
}'
Lextree answers 200 with the updated record. A PATCH that changes nothing writes nothing, so it leaves no audit entry.
Send a batch
When you have several changes, send them together. POST /api/v1/boards/batch takes up to 25 items, which can be creates, updates, trashes, restores and purges in any mix. Lextree validates every item first and runs them as one transaction: if any item fails, nothing is written. A batch needs an Idempotency-Key like a create does.
Each item names its operation in op. A create carries data. An update carries the record’s id and data:
curl -X POST https://us.lextree.ai/api/v1/boards/batch \
-H "Authorization: Bearer $LEXTREE_KEY" \
-H "Idempotency-Key: c4f81b36-0d27-4a9e-8e53-6b7a1f90d2e4" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"op": "create",
"data": {
"name": "Sustainability committee",
"entity_id": "f0348da1bc614dc3bab5d1b3c0aa8d3c"
}
},
{
"op": "update",
"id": "5ab3e7c9d2f14860b7194e0a6c83d5f2",
"data": {
"custom_fields": {
"meeting_frequency": "Monthly"
}
}
}
]
}'
The 200 response holds one row per item, in the order you sent them. A purge item yields null in its place.
Read the errors
When a batch item is invalid, Lextree refuses the whole batch with 422 batch-failed and names the item’s position in index. This batch leaves out the required entity_id:
curl -X POST https://us.lextree.ai/api/v1/boards/batch \
-H "Authorization: Bearer $LEXTREE_KEY" \
-H "Idempotency-Key: 91e0b5d7-6a3c-4c12-b8f4-2d57a09c1e63" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"op": "create",
"data": {
"name": "Ethics committee"
}
}
]
}'
{
"type": "urn:lt:api:errors:batch-failed",
"title": "Batch failed validation",
"status": 422,
"detail": "1 error(s) across the batch; nothing was written.",
"instance": "/api/v1/boards/batch",
"request_id": "42284802467f432da7c95b01bb47e4e7",
"errors": [
{
"field": "entity_id",
"code": "required",
"message": "Governed organization is required.",
"index": 0
}
]
}
Every error follows this shape. Branch on the type value, and read detail and errors to learn what to fix.
A request your key’s scope doesn’t allow gets 403 insufficient-scope. Purging a board with the Read and write key you created here is one example:
{
"type": "urn:lt:api:errors:insufficient-scope",
"title": "Insufficient scope",
"status": 403,
"detail": "This API key is not purge-scoped. Scope is chosen when a key is created; create a new key with the scope you need and revoke this one.",
"instance": "/api/v1/boards/5ab3e7c9d2f14860b7194e0a6c83d5f2/purge",
"request_id": "cbf4cefe2b774cc78911cf2d4008913c"
}
Where to go next
The API reference, linked from the Swagger UI at /api/v1/docs on your Lextree address, covers everything this walkthrough skipped. These are the places to look next:
- Filtering records with
filter[...]parameters, and paging through large result sets. - Writing events, timeline entries, attachments, reports, charts and workflow launches, with the same idempotency rules.
- The trash view, restore and purge, for syncing deletions.
- Configuration access, for keys that set up custom fields, sections and templates.
- Reference data:
GET /api/v1/reference/countries,/reference/subdivisions?country=USand/reference/legal_forms?jurisdiction=US|US-FLlist the codes thatcountry,country_subdivisionandlegal_formvalues use. - Write formats for field values: the shape a read returns is always accepted back on a write, and each field’s
typein the record type’s/schematells you which write form applies. The full API reference has the table of formats for every type, including the few traps, such as apercentreading as a fraction so that a bare19means 1,900%. - Rate limits: your subscription shares one token budget across all its keys, and a request that exceeds it returns
429with aRetry-Afterheader. TheGET /api/v1/usagecall reports your current headroom. The response also identifies the subscription the key belongs to (subscriber.idandsubscriber.name) and what the key may do (api_key.can_write,can_purgeandcan_configure), so read it before your first write to check that you are in the right subscription.
The same key also works with an AI assistant over MCP. The API Access page describes the two addresses and how a write session is scoped.