← All articles

From PDF to Reliable JSON: Define the Extraction Contract Before the API

Define field meaning, missing-value behavior, source evidence and acceptance rules before connecting document extraction to a downstream application.

A document-extraction demo can return convincing JSON and still leave the receiving application unsure what to do. Is total the amount before or after tax? Does an empty field mean the document omitted it, the text was unreadable, or the extraction failed? Can a downstream service safely accept a newly added field?

These questions belong in an extraction contract: an agreement between the document workflow and the application consuming its output. Define it before wiring the endpoint into a production process. Otherwise, every new document layout can become an integration decision made at runtime.

This guide describes a suggested application design, not a claim that any extraction product implements all the checks below. The invoice examples and values are fictional.

1. Start with the downstream action

“Extract everything” is a weak specification. Start with the next action: reconcile a supplier invoice, populate a review screen, or prepare a record for an approved workflow. Then identify the smallest set of fields that action needs.

For each field, write down:

  • Meaning: the exact business concept, including exclusions.
  • Source: the document section or label that should support it.
  • Representation: type, units, currency and normalization rules.
  • Uncertainty: what happens when evidence is missing or ambiguous.
  • Acceptance: the conditions under which the consumer may use it.

For example, define amount_due as the amount the document says remains payable, rather than silently substituting the invoice total. A deposit, credit or previous payment may make those values different. Keep invoice identifiers as strings so leading zeros survive.

Have the receiving application's owner review this specification. A field name that makes sense to the extraction team may mean something different in the system of record.

2. Separate response structure from business completeness

A JSON Schema describes constraints on JSON instances. It can help check types, required properties and allowed values. It cannot, by itself, establish that a value came from the correct region of a PDF or represents the business concept you intended.

Two defaults are easy to overlook: listing a name under properties does not make it required, and additional properties are allowed unless you constrain them. Both are explained in the official JSON Schema object reference.

An illustrative boundary schema for one extraction field can specify:

  • Response type: an object describing one extraction field.
  • value: a string or null.
  • state: one of extracted, not_found or needs_review.
  • Required properties: both value and state must be present.
  • Additional properties: disallowed in this minimal version.

This minimal example omits evidence and reason fields; declare those properties when extending the envelope. It checks the shape, not every valid combination. A second rule must reject state: "extracted" with a null value. Add conditional schema rules or application validation where appropriate, and test the validator you actually deploy.

Also distinguish “this key must be present in a successful response” from “this business value must be available before processing.” A required key can carry a null value when the schema permits it, while the workflow still routes the record for review.

3. Make missing, null and unreadable explicit

JSON Schema distinguishes null from an absent property. Your contract should explain what each means in your application.

One workable convention is:

  • extracted: the pipeline found a candidate value with source evidence. Validation still follows.
  • not_found: the pipeline completed but did not locate the field. This is not proof that it is absent from every page.
  • needs_review: competing, unreadable or otherwise uncertain evidence prevents a reliable choice.

For a requested field in a successful response, always return the field envelope. Use value: null for unresolved values and include a reason. Reserve a missing envelope for a contract violation, rather than giving it an undocumented meaning. Report request-level failures separately; a timeout should never masquerade as a document with no invoice number.

Do not use an empty string, zero or a fabricated date as a universal fallback. Zero may be a genuine amount. Filling a blank with a plausible value hides the very uncertainty the receiving team needs to see.

4. Preserve the evidence behind normalization

Normalized values are convenient for software; the original representation is useful for review. Keep both when the workflow warrants it, with access and retention appropriate to the source data.

An illustrative application record could contain the following fields. This is not a GritTransform API response:

  • contract_version: invoice-intake/1.0.
  • source_document_id: fixture-017.
  • amount_due.raw: USD 1,240.00, preserving the displayed amount.
  • amount_due.value: the decimal string 1240.00.
  • amount_due.currency: USD.
  • amount_due.state: extracted.
  • amount_due.source: page 2, beside the label Amount due.

This design uses a decimal string for money. Other systems use integer minor units or a decimal type after parsing. Choose one convention deliberately and document currency-specific handling; do not make a consumer guess whether 124000 means dollars or cents.

For dates, 03/04/2026 is ambiguous without context. Preserve the raw text and route uncertainty rather than assuming a locale. Agree how localized numbers, parentheses for negative amounts, multi-line names and repeated labels should be handled.

If you use a schema's format keyword for dates, check your implementation. JSON Schema documents that format is an annotation by default, with validation behavior depending on configuration. A field declaration alone is not evidence that date validation ran.

Source page numbers and labels help a reviewer find evidence, but they can also be wrong. Test the source reference against the actual page. Avoid copying entire sensitive passages into broadly accessible logs just to make debugging easier.

5. Apply acceptance checks in layers

Use separate checks so a failure has a clear owner and response:

  • Transport and parsing: did the request complete and return parseable JSON?
  • Contract: are required envelopes, types and enumerations correct?
  • Evidence: does the source support the extracted value and its meaning?
  • Business rules: do relevant fields agree under this workflow's rules?
  • Disposition: accept for the intended next step, send for review, or reject with a useful reason.

For an invoice, arithmetic checks might compare line items, tax, credits and stated totals under an agreed rounding policy. The rule must account for the document's actual conventions rather than imposing one formula on every supplier. Cross-document identifiers require separate reconciliation; a valid JSON string does not establish that two records belong together.

A high confidence score should not override a failed critical check. Likewise, valid output should not automatically authorize a payment, eligibility decision or disclosure. Keep those business decisions in the appropriate governed workflow.

For extraction-quality measurement itself, use the companion field-level OCR evaluation guide. The contract determines what the application accepts; the evaluation determines how reliably the extraction produces it.

6. Version the contract and test the exceptions

Before connecting a consumer, build a small fixture set with expected outputs and dispositions. Include a leading-zero identifier, a missing mandatory business value, an ambiguous date, conflicting totals, a duplicate document and a previously unseen optional field.

Run those fixtures through both extraction and the receiving application's validation. Check that a retry cannot silently create a second business record, using the identity and duplicate policy appropriate to your system.

Decide how schema evolution works. Rejecting unexpected properties catches accidental changes, but can also break an older consumer when a harmless field is added. An alternative is a documented extension area or consumers that explicitly tolerate unknown optional fields. Neither choice is universally correct. Test compatibility, identify affected consumers and version changes to field meaning as carefully as changes to type.

Keep a release record linking the contract version, extraction configuration, fixture set and acceptance results. That makes a changed outcome diagnosable without assuming the document alone caused it.

Put the contract to work

GritTransform lets teams configure fields for PDF and image extraction, review values with source highlighting, save projects and deploy named API endpoints. The application-level contract and acceptance rules described here still need to be defined and tested for your workflow.

Start with a representative, approved sample, a field dictionary and examples of outcomes that must be reviewed rather than accepted. If that is the gap your team is working through, discuss the extraction workflow with GritWorks. Do not send sensitive production documents through a public contact form or email.

KEEP READING

More perspectives on enterprise unstructured data.

Browse the blog