Consumer SDK
One call, one JSON object.
Hand understand() your files and the JSON Schema you want back. The platform returns a result in that shape, grounded against the inputs before it reaches you.
The call
import json
from convilyn import Convilyn
client = Convilyn()
file = client.files.upload("invoice-2026-03.pdf")
result = client.goals.understand(
[file.file_id],
schema=json.load(open("invoice.schema.json")),
instructions="Amounts are in the invoice's own currency; do not convert.",
)
print(result["invoice_number"], result["total"])TypeScript SDK is in pre-release — see its reference section.
Accepts documents (pdf, docx, doc, pptx, ppt, txt, md) and
images (png, jpg, jpeg, webp), up to 50 MB each, as file ids from
files.upload.
Returns the parsed JSON conforming to your schema. Not a job handle — the call drives the run to completion and hands you the object.
Why a JSON Schema, and not a model class
A Pydantic model would be more idiomatic in Python and useless everywhere else.
JSON Schema is language-neutral, so the same invoice.schema.json drives the
Python SDK, the CLI, and every other language binding — and the SDK adds no
validation dependency to your install to support it.
It is also why extract() is deprecated. That call ran one fixed workflow and
returned whatever shape it happened to emit; the caller had no say. Passing the
shape in is the whole difference.
Design the schema for grounding, not for completeness
This is the part that decides whether you get reliable output, and the instinct
to mark everything required is the wrong one.
Before — every field required:
{
"type": "object",
"required": ["invoice_number", "total", "discount_reason", "line_items"],
"properties": {
"invoice_number": { "type": "string" },
"total": { "type": "number" },
"discount_reason": { "type": "string" },
"line_items": { "type": "array", "items": { "type": "object" } }
}
}An invoice with no discount now forces a choice between an empty value and an invented one. You have asked for a field the document cannot support.
After — required means "this document must contain it":
{
"type": "object",
"required": ["invoice_number", "total"],
"properties": {
"invoice_number": { "type": "string" },
"total": { "type": "number" },
"discount_reason": { "type": ["string", "null"] },
"line_items": { "type": "array", "items": { "type": "object" } }
}
}Reliability here is the server's guarantee rather than something you tune per call — but only for shapes the source can actually support.
More best practice:
- Ask for the narrowest schema that answers your question. Fields you do not read are fields that can be wrong.
- Use
instructionsto steer, not to restate the schema. The shape is already fixed; the sentence is for the things a schema cannot say — which currency, which date convention, what to do with a struck-through line. - One file per call where you can. It is the case the platform handles most directly.
- Check
client.account.get_quota()before a batch, not after.
What can go wrong
| Raised | Means | Do |
|---|---|---|
UnderstandUnavailableError | This deployment does not accept schema-constrained requests | Fall back to a workflow, or wait for enablement |
ValueError / TypeError | Empty files, or schema is not a JSON Schema object | Fix the call — raised before any network use |
GoalJobFailedError | The run started and failed | Inspect the error; retry is not automatic |
GoalJobTimeoutError | The deadline elapsed | The run survives — poll it, or raise timeout |
The first row is the important one: an answer that was not grounded is never returned as though it were. A capability that is off fails loudly rather than degrading into a plausible guess.
From the shell
convilyn goals understand \
--files file_abc \
--schema-file invoice.schema.json \
--instructions "Amounts are in the invoice's own currency" \
--json--dry-run validates the schema file and exits without a network call. A schema
that is missing, unreadable, or not a JSON object fails before anything is
sent — including under --dry-run, because a preview that skipped validation
would be lying about what a real run does.