Skip to main content
Higher-Order Extraction returns values calculated from other fields in a document, including answers that aren’t printed on the page. Each calculated field comes back with the source values it used and where each source value appears on the page.
A University of South Carolina pay stub shows 54.17 hours and $839.64 in earnings but no hourly rate. Both values are highlighted, and the hourly rate is calculated as $839.64 divided by 54.17 hours, giving $15.50 per hour.
This feature is in beta. The playground and API call it calculated fields or computed fields. In the extraction playground, turn on Calculated Fields. For API requests, pass enable_computed_fields=true to /v2/extract.
By the end, we’ll have a script that sends a pay stub to /v2/extract, asks for an hourly rate that the stub doesn’t print, and saves the calculated rate with the hours and earnings it came from. Grab the full script from the dropdown below if you’d rather skip the walkthrough.
Set UNSILOED_API_KEY in your environment, and save the sample pay stub as pay-stub.png and the schema from Step 2 as schema.json in the same directory before running.
extract_calculated_fields.py

Step 1: Set Up Your Environment

We need an API key, the sample document, and Python’s requests package. The Extract quickstart covers the first and last of these in more detail.

1.1 Export Your API Key

Export your key as an environment variable named UNSILOED_API_KEY:

1.2 Download the Sample Pay Stub

Download the sample pay stub and save it as pay-stub.png in your working directory. The stub’s Hours and Earnings table totals 54.17 hours and $839.64 for the pay period, but the stub doesn’t print an hourly rate. That’s the value we’ll calculate.

1.3 Install Dependencies

Install the requests package:

Step 2: Describe the Calculation

A calculated field is an ordinary schema field whose description says how to combine other fields. It uses the same JSON Schema rules as the rest of the schema, and you don’t supply any executable code.

2.1 Add the Input Fields

Create a file called schema.json and add a field for each value the calculation needs:
schema.json
These are normal extraction fields. Each description points at one printed value, so the API knows exactly which number to read.

2.2 Add the Calculated Field

Finish the file with the calculated field:
schema.json
The description does three jobs:
  • It names the input fields by their keys, current_earnings and current_hours.
  • It states the operation, dividing one by the other.
  • It says the value isn’t printed, so the API calculates it instead of searching the page for it.
In your own schemas, also include units and any rules the calculation depends on.

Step 3: Submit the Document

The request is a normal /v2/extract call with enable_computed_fields set to true. We also set enable_citations to true so that each input comes back with its location on the page.

3.1 Set Up the Script

Create a file called extract_calculated_fields.py and start with the imports, configuration, and schema:
extract_calculated_fields.py

3.2 Upload the Pay Stub

Next, upload the pay stub and schema, then print the job ID:
extract_calculated_fields.py
The file goes in the pdf_file form field even though it’s a PNG.

Step 4: Poll for the Result

Calculated fields add a stage to the job. Processing time varies from seconds to several minutes, so allow a longer timeout than you would for ordinary extraction.

4.1 Write the Polling Loop

Next, poll every 10 seconds for up to 20 minutes:
extract_calculated_fields.py
If the loop times out, keep the job ID and check its status later rather than submitting the document again.

4.2 Save and Print the Result

Finally, save the full response and print the calculated rate:
extract_calculated_fields.py
Run the script:
The output looks like this:

Step 5: Read the Calculated Result

Open result.json. The hourly_rate field holds the answer, the inputs it used, and the checks the API ran.

5.1 Check the Outcome

  • computed.outcome is calculated when the field has a value. Check it before you use value.
  • computed.explanation states the calculation in plain language.
  • computed.inputs_used and computed.inputs_empty count the inputs that had values and the inputs that were empty.
  • citation is null because the hourly rate isn’t printed anywhere to point to.
The value isn’t rounded. Round 15.500092302012185 to 15.50 in your application if you need a currency amount.

5.2 Trace the Inputs

Each input names its source field by path and gives the value used. The citation box shows where that value appears on the page, so you can verify the calculation against the document. An input’s citation is null when enable_citations is false. Drawing the two boxes on the sample pay stub highlights the TOTAL row values:
The Hours and Earnings table on the sample pay stub, with the current_hours box around 54.17 and the current_earnings box around 839.64 on the TOTAL row.

5.3 Review the Checks

printed_value compares the result against a matching value printed in the document, and formulas_agree compares alternative formulas. Both are not_run here, so neither validated this answer.

Handle Refused Calculations

A job can finish with status: "completed" while a calculated field is refused. For example, changing the hourly_rate description to ask for the rate “rounded to the nearest cent” returned this field:
The beta doesn’t support every calculation. In testing, rounding and counting the days between two dates were both refused. A refused field has a null value, so treat it as missing, not as zero. Read cause and detail to decide whether to revise the field’s description or calculate the value in your application from the extracted inputs.