Skip to main content
This example reads a contract, extracts its key terms and the clauses it contains, and then runs a set of rules over those terms. Four deterministic rules catch a missing date or a short notice period for free. One AI rule judges whether the indemnification clause protects you.
The contract
MASTER SERVICES AGREEMENT
What comes back
contract_type96%
auto_renewal96%
notice_days97%
liability_cap95%
key_clauses94%
NodesCredits60 per pageYou get

The workflow

Upload now, run later, poll

Contracts often arrive in batches and get reviewed later. Upload each one as a document packet as it arrives, and start the run when you are ready. Then poll GET /v3/runs/{run_id}/ until status is processed. error and cancelled are terminal too, so stop on those.

Response

The results envelope of a processed run, trimmed. Every value is a string on the wire: a multi_select is one comma-separated string of option names, with one evidence snippet per clause, and a boolean is "True" or "False".
Response
Every field also carries verification_status and value_override. Runs and results has the full envelope, section by section. Rule outcomes (pass, fail, inconclusive) appear in the Validation tab of the run in Studio, next to the extracted values. On this contract notice-at-least-90-days fails, because the notice period is 60 days. To act on a failure automatically, route the run with an If/Else node and send a Slack alert or an email alert.

When it goes wrong

A clause you care about never appears in key_clauses. A multi_select returns only the option names you declared, so an assignment clause or a most-favoured-nation term has nothing to match among the seven listed here. Add the option. Remember the field tells you a clause is present, not what it says: add a string field for each clause whose wording you need to read. key_clauses is one string, not a list. Every value is a string on the wire, and a multi_select arrives as its option names joined with ", ". Split on that before you test for membership. A boolean behaves the same way: auto_renewal comes back as "True", not as JSON true. A range rule has nothing to compare. A range check needs the number you declared. Declare termination_notice_days as integer, so { "type": "range", "min": 90 } compares numbers and your calendar math works on the value directly. Declare effective_date and expiration_date as date for the same reason: term-is-ordered compares them. A failed rule did not stop anything. severity is a label. A failed error rule never blocks the run; it tells the reviewer where to look first. Read the outcomes in the Validation tab of the run in Studio. To act on a failure automatically, route the run with an If/Else node and end that branch in a Slack alert. Validation costs more than you expected. An AI rule costs 5 credits, billed once per rule per extraction, not per page. A deterministic rule, including an expression, costs nothing. Use a deterministic rule for anything a calculator can check: it is instant, free and never flakes. A required check on liability_cap is the cheapest way to flag an uncapped contract. Keep AI rules for judgement calls, like whether the indemnification clause protects the Client.

Next steps

Validate node

Every check type, expressions and severities

Run document packet

Run or re-run a packet you uploaded earlier