Oktopeak
Legal Tech June 3, 2026 · 12 min read

Recipe: Blank Auto-Generated Document to First Draft, Pre-Filled From Structured Fields

Here's a problem a lot of small firms share. Your practice-management system auto-generates the documents you need when a matter hits a certain stage. They come out blank. Meanwhile, the data those documents want is already sitting in your custom fields. This recipe connects the two: read the structured field values, have Claude pre-fill the draft, and put it back in the matter for review. It's based on the real API behavior and failure modes we hit building our open-source Clio and MyCase connectors.

By Petar Jovanović · Co-Founder & Technical Lead

The frustration is specific. You set up document automation in Clio, so when a case reaches a litigation stage the right forms generate themselves. Good. Except the forms are mostly empty. Maybe the client name and address carry through. The hundred-plus custom fields you've carefully maintained on that matter, the ones holding the actual substance, don't flow into the document. So you sit there typing values into a form that already exists in structured form three clicks away.

The data is right there. It just isn't connected to the place it belongs. That gap is what this recipe closes.

Two things up front. First, this is about the mechanical fill, taking values you already have and placing them in the right slots, not about asking AI to decide what's legally relevant. That's a different problem and a much harder one. Keep the judgment with the lawyer. Second, we learned the specifics building the @oktopeak/clio-mcp and MyCase MCP connectors that let Claude talk to legal practice-management systems. The traps below are the ones that cost us time so they don't have to cost you a weekend.


The recipe at a glance

Four stages. Each one carries a decision, and the right answer depends on your stack and your data, not on us.

  1. Read the structured data. Pull the matter's custom field values out of Clio (or MyCase, or PracticePanther).
  2. Normalize what's messy. Clean inconsistent values to a standard format, but only for the field types that allow it.
  3. Fill the template. Map each field into the right slot in the generated document with Claude, producing a first draft instead of a blank one.
  4. Close the loop. Upload the filled draft back into the matter for the lawyer to verify.

The hard parts are the custom-field write mechanics, knowing which fields you can safely normalize, and getting the data-handling posture right. We'll go through each.


Stage 1: How do you read custom field values out of Clio?

The Clio Manage API supports reading and writing custom fields. You read them by asking for them explicitly: GET matter?fields=custom_field_values{...}. By default the matter response won't include the custom field values, so you have to request the nested object. There's no practical cap on how many fields a matter carries; a couple hundred is fine.

One honest caveat if you're using a tool layer like an MCP connector rather than calling the API directly: not every connector exposes custom fields. Ours didn't at first, and there was no generic matter-update tool either. Reading and writing custom fields was net-new connector work, not a config flip. So before you assume your tooling can do this, confirm it can actually list, read, and write custom field values. A connector that can read matters but not their custom fields will leave you exactly where you started.


Stage 2: The write trap that breaks almost every first attempt

This is the one that will eat your afternoon. Writing a custom field value is a PATCH to the matter with a nested custom_field_values array. Simple enough. The trap is which id goes in that array.

The value-instance-id-vs-field-id trap. The id inside custom_field_values is the value-instance id, the id of the value already attached to that specific matter, not the field-definition id (the global custom_field id that defines the field). Send the field-definition id and your update fails or writes the wrong thing. This is the single most common Clio custom-field integration bug, and the error message rarely tells you that's what happened.

The fix is an ordering rule. Read the matter first, capture the value-instance ids that come back in custom_field_values, then build your PATCH against those ids. Don't try to write blind from a list of field definitions. We bake this read-then-write pattern into the connector tool so the value-instance id is resolved for you, but if you're calling the API yourself, this is the line of code to get right before anything else.


Stage 2.5: Which fields can you actually normalize?

Here's the appeal of doing this at all: clients write the same thing different ways. A street address entered three different ways across three matters, when the court wants one specific format. Free-text fields are where Claude shines. Messy entry in, your standard format out, every time, enforced by the prompt and the code instead of by hoping people follow a style guide.

But "normalize all my fields" is a promise you can't keep, because field type constrains what's legal to write. This catches people who assume a custom field is just a string.

Clio custom field types and what normalization can do

Field type Constraint Normalization approach
Free text None LLM normalizes cleanly to your standard format
Picklist Predefined options only, 55 chars max Map a messy value onto an existing option, never invent one
Currency Rejects unexpected decimal formats Coerce to the accepted numeric format before writing
Date Needs a valid date Parse and reformat; reject anything that isn't a real date

So the real first step is an inventory. Pull every custom field by type before you promise blanket normalization. A free-text rule applied to a picklist field gets rejected, and if you didn't expect that, your batch run dies partway through with confusing errors. Knowing the type map up front is the difference between a smooth run and a forensic debugging session.


Stage 3: How do you fill the template, when Clio's own automation is UI-only?

This is the part where the obvious approach doesn't exist. Clio's document automation, the feature that generates the blank document in the first place, is UI-only. There's no API to trigger it, no API to fill it. You can't call Clio and say "generate this template and populate field X." So pre-filling can't mean driving Clio's own document engine.

What works instead: read the matter's custom field values through the API, hand them to Claude alongside the document, and have Claude place each value in the right slot. The prompt is fixed, which is the whole point. A consistent mapping produces a consistently structured first draft every time, across every matter and every lawyer who uses the workflow. The model isn't deciding what's relevant. It's doing reliable, repeatable placement of data you already structured.

If you also need to react to Clio generating a new blank document (to know there's a fresh template waiting to be filled), know that Clio has no document webhook. Webhooks exist for activity, bill, calendar_entry, communication, contact, matter, and task, not documents. The generation is usually caused by a matter stage change, so you subscribe to the matter updated webhook and trigger on the stage change that produced the document, or you poll. And Clio webhooks auto-expire (3 days default, 31 max), so a renewal job isn't optional.


Stage 4: How do you put the filled draft back into the matter?

People assume this is hard. It's well-defined, as long as you know it's a three-step flow and not a single upload call. Clio uploads go through a presigned S3 PUT:

  1. POST /documents to create the document record. Clio returns a put_url.
  2. PUT the filled file bytes directly to that S3 URL.
  3. PATCH the document with fully_uploaded set to true.

The trap: skip that final PATCH and the document exists in Clio but shows as incomplete. The bytes are in S3, the record points at them, but until you mark it fully uploaded it doesn't behave like a real document. Our connector's upload_document tool wraps all three steps so this can't be half-done. If you build it yourself, write a test that confirms the document opens after upload, not just that the API returned 200.


Doing this across hundreds of matters: rate limits and resumability

Filling one document is trivial. Normalizing fields or filling drafts across an entire book of matters is where the platform pushes back. Clio's rate limit is conservative: budget for roughly 3 requests per second per app (the docs also cite a 50-per-minute legacy figure). Honor the X-RateLimit-* headers, back off on 429s, and paginate at 200 records per page.

At three requests a second, a read-normalize-write pass over hundreds of matters is a long job, not an instant one. Two design rules follow from that. Make the batch resumable, so a 429 or a network blip three hundred matters in doesn't force you to start over or, worse, double-write. And build a dry-run preview plus per-matter rollback before you let it write to live data. Showing exactly what would change, matter by matter, is how the firm trusts the run before it touches the file. Writing to live client matters with no preview and no undo is how you turn a time-saver into an incident.

One more access gotcha: the OAuth user running the batch must have write access to every matter it touches. If a matter is restricted and the integration user can't write it, that matter silently fails. Check scope before the run, not during.


Where should the data go: privacy and region

If you're handling privileged client data, the model surface matters. The honest version, because the marketing version gets it wrong:

  • Zero data retention is not available on the Claude Team plan. That's a product limitation, not a small-firm rejection. People assume Team is the privacy tier and it isn't, for this.
  • ZDR is available on the Anthropic API, granted at the organization level, and a small firm can obtain it. Route the automated fill through the plain Messages API under a ZDR arrangement, training off by default.
  • There's no Canadian Claude region. Inference is US-only at rest. For Canadian firms under PIPEDA, the cross-border step is unavoidable. The honest move is to state it: ZDR plus a US inference pin means content isn't stored at rest after the response, and you document the cross-border processing as part of your confidentiality obligations.
  • ZDR covers plain Messages-API calls. Keep the pipeline off the surfaces it doesn't cover (the Files API, Batch, code execution, the hosted MCP connector). Pass field values inline on the Messages API rather than routing them through the Files API for convenience.

This matters more here than you'd think, because the data you're moving is the structured substance of a matter, not just a name and address. Treat it accordingly.


The human-review gate is not optional

The filled document lands in the matter as a draft for a lawyer to verify, never as a finished or filed document. This isn't a nicety. The ABA's Formal Opinion 512 and the Law Society of Ontario's guidance both point the same direction: confidentiality, competence, supervision, and mandatory human verification of AI outputs. You also can't bill AI processing time as lawyer hours.

That boundary is also a clean product boundary. The automation handles the mechanical population, the part you'd happily never touch again. The lawyer keeps every decision about what's legally relevant and whether the draft is right. As one boundary we'd never cross: don't ask the system to decide what belongs in the document. Ask it to place data you already structured. The judgment stays human.


Build it yourself or have it built?

If you're technical, every piece here is documented and buildable. The connectors are open source. The Clio Manage API is well-trodden. You could wire this up.

What you're really weighing is your time against reliability and replication. The reasons to build the automated version are the consistent mapping, the field-type-aware normalization, the safe batch with preview and rollback, and the ability to deploy the same workflow to every lawyer on a team without each of them doing tech setup. Most lawyers won't, and shouldn't have to.

This is also why a generic n8n flow or an off-the-shelf "AI legal assistant" tends to fall short here. The value-instance-id write, the field-type constraints, the UI-only document automation, the presigned-upload PATCH, the 3-req/s throttle and resumability, the ZDR surface boundaries: these decide whether it works in production or fails the first time someone runs it across a real book of matters. They don't show up in a demo. They show up in week three. Agencies that quote this without naming them, ourselves included before we'd built the connectors, are quoting a demo, not a system.


Frequently asked questions

Can you read and write Clio custom field values through the API?

Yes. You read them with GET matter?fields=custom_field_values{...} and write them with a PATCH to the matter that includes a nested custom_field_values array. There's no practical limit on field count; a couple hundred is fine. The biggest trap is the id you send when writing: it's the value-instance id of the existing value on that matter, not the field-definition id. Send the field-definition id and the write fails or creates the wrong thing.

Why does my Clio custom field update fail with a valid field id?

Because you're almost certainly sending the field-definition id when the PATCH wants the value-instance id. The custom_field_values array references the id of the value already attached to that specific matter, not the global custom_field id that defines the field. This is the single most common Clio custom-field integration bug. Read the matter first, capture the value-instance ids, then PATCH against those.

Can Claude fill in blank Clio document templates automatically?

Not by triggering Clio's own document automation, which is UI-only with no API to generate or fill a template. The workable pattern is to read the matter's custom field values through the API, have Claude map them into the document, and upload the filled draft back into the matter through the three-step presigned-S3 flow. Clio's automation makes the blank document; the API plus Claude makes the filled draft.

What are the Clio API rate limits for a large batch job?

Budget conservatively for about 3 requests per second per app (Clio's docs also cite a 50-per-minute legacy figure). Honor the X-RateLimit-* headers, back off on 429 responses, and paginate at 200 records per page. Reading and writing across hundreds of matters means a long, throttled run, so build the batch to be resumable rather than assuming it finishes in one pass.

Will Claude normalize any custom field, or only some?

Only some cleanly. Free-text fields normalize well: messy entry in, your standard format out. But picklist fields can only hold predefined options up to 55 characters, currency fields reject unexpected decimal formats, and date fields need valid dates. Inventory your fields by type before promising blanket normalization, because a free-text rule applied to a picklist field will be rejected.

Should an AI-filled legal document be reviewed before it's used?

Always. ABA Formal Opinion 512 and Law Society of Ontario guidance both call for confidentiality, competence, supervision, and mandatory human verification of AI outputs, and you can't bill AI processing time as lawyer hours. The filled document lands as a draft for the lawyer to verify and finalize. Automate the mechanical field population; keep the legal judgment with the lawyer.


Next step

We build these workflows for law firms on Clio and MyCase, and we maintain the open-source connectors that make them possible. If you're staring at blank auto-generated documents and a pile of custom fields that should be filling them, and you want a sanity check on the architecture before you commit to building, we'll give you an honest read.

Book a 30-minute workflow review →

Or explore more from our legal AI integration work:

Petar Jovanović

[ WRITTEN BY ]

Petar Jovanović

Co-Founder & Technical Lead

Co-Founder and Technical Lead at Oktopeak. Builds regulated software for legal and healthcare teams, and leads the rescues of codebases other vendors left half-finished.

[ LEGAL TECH ]

Related Articles

[ GET STARTED ]

Ready to build?

30-minute call. No pitch deck. Just an honest conversation about your project.

Book a call
Talk with a friendly expert