Skip to content
API console (try a request with your own key)Get early access

Reading results

GET /v1/extractions/{jobId}/sheets/{sheetNumber} answers one sheet’s values; sheetNumber 1 is the file’s first page. A sheet not read yet answers with its status and no values.

read_fields.sh
#!/usr/bin/env bash
set -euo pipefail
API=https://api.speccapture.com
AUTH="Authorization: Bearer $SPECCAPTURE_API_KEY"
JOB_ID=7c9e6679-7425-40de-944b-e07fc1f90ae7 # the jobId the submission answered with
SHEET_NUMBER=1 # which sheet: 1 is the first page
sheet=$(curl -sS --fail-with-body "$API/v1/extractions/$JOB_ID/sheets/$SHEET_NUMBER" \
-H "$AUTH") || { echo "$sheet" >&2; exit 1; }
jq -r '"Sheet \(.sheetNumber) is \(.reviewState)"' <<<"$sheet"
jq -r '.fields[] as $field | (" \($field.path) = \($field.value // "(not on the sheet)") (\($field.confidence))", if $field.reviewState == "needsReview" then " needs a look" else empty end)' <<<"$sheet"

Save as read_fields.sh, set SPECCAPTURE_API_KEY, and run: bash read_fields.sh. Needs curl; scripts also use bash and jq.

A sheet’s values, shortened to one field, one table cell and one general note:

{
"jobId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"sheetNumber": 1,
"status": "completed",
"reviewState": "needsReview",
"engineVersion": "ev1-3684d4286e2783c2",
"completedAt": "2026-10-12T09:01:00+00:00",
"fields": [
{
"path": "titleBlock.partNumber",
"value": "SG-2001",
"extractedValue": "SG-2001",
"confidence": 0.97,
"reviewState": "autoAccepted",
"reviewReasons": [],
"box": {
"points": [
{ "x": 0.6367, "y": 0.8016 },
{ "x": 0.6698, "y": 0.8016 },
{ "x": 0.6698, "y": 0.8248 },
{ "x": 0.6367, "y": 0.8248 }
]
}
}
],
"tables": [
{
"path": "revisionHistory",
"rows": [
{
"rowIndex": 0,
"cells": {
"rev": {
"path": "revisionHistory[0].rev",
"value": "B",
"extractedValue": "B",
"confidence": 0.62,
"reviewState": "needsReview",
"reviewReasons": ["HandwrittenInk"],
"box": null
}
}
}
]
},
{
"path": "generalNotes",
"rows": [
{
"rowIndex": 0,
"cells": {
"value": {
"path": "generalNotes[0]",
"value": "1. REMOVE ALL BURRS AND SHARP EDGES.",
"extractedValue": "1. REMOVE ALL BURRS AND SHARP EDGES.",
"confidence": null,
"reviewState": "needsReview",
"reviewReasons": [],
"box": null
}
}
}
]
}
],
"testMode": false,
"markedControlled": false,
"controlledMarking": null,
"drawingPurgedAt": null,
"controlledKept": null
}
  • reviewState is the sheet’s: autoAccepted (every value cleared the confidence threshold and nothing asked for a look), needsReview (at least one value, or the sheet as a whole, waits for a person), or reviewed (a person has accepted or corrected every value that needed it).
  • engineVersion names the version of the engine that read the sheet, so two readings can be told apart.
  • markedControlled is true, and controlledMarking says which control, when the sheet’s own export-control marking names one: Distribution Statement B to Distribution Statement F (or the old Distribution Statement X), ITAR, EAR, CUI, NOFORN, FOUO, or export-restricted for a warning that the drawing’s export is restricted. Otherwise false and null. The job’s sheets carry the same two. See Not for export-controlled drawings.
  • controlledKept is the workspace’s decision to keep a marked drawing - { "at", "by", "reason" }: when, who (as the workspace’s people list names them, null once they have left it) and why, in their words - once its owner or an admin made it in the dashboard. It stays null while the warning stands, and on a sheet that is not marked; markedControlled stays true, since the sheet says what it says. The decision covers the whole document, and an integration quarantining marked sheets can release the kept ones. The job’s sheets and the webhook payload carry it too.
  • fields holds the values that occur once on a sheet, such as titleBlock.partNumber; tables holds the rows of each table.
  • drawingPurgedAt is when the workspace’s retention period removed the drawing, and every value’s box with it; null while the drawing is kept. The job carries it too. See How long the drawing is kept.
Property What it is
path Which value this is: titleBlock.partNumber. Every path is listed under Field paths. Use it as the key: it never changes.
name What the job’s template calls it: Part Number, or the workspace’s own name for it. A table cell’s is its column’s; a note’s is Note.
value The value as it stands: a reviewer’s correction when there is one, otherwise what was read. null means it is not on the sheet.
extractedValue What SpecCapture read, before any correction.
confidence How sure the reading is, from 0 to 1. null for a general note: a note is copied whole, as printed, and not scored.
reviewState autoAccepted (delivered with nothing asking for a look), needsReview (delivered, and waiting for a person), accepted (a person confirmed it as it stands) or corrected (a person replaced it; value is the correction).
reviewReasons Why the value asks for a person, such as HandwrittenInk, or RequiredButNotFound when the job’s template requires the field and the drawing does not give it.
box Where on the sheet it was read: { "points": [{ "x", "y" }, ...] }, in page coordinates from 0 to 1 with the origin at the top left, so it fits the page at any size. null when the value has no single place on the sheet, and for every value once the drawing is no longer kept (the sheet’s drawingPurgedAt says when).

Values are given as the drawing prints them: a dimension printed .375 +.002 -.000 comes back as exactly that, not as a number worked out from it. A value waiting for review (needsReview) is delivered as read so your software can show it, but nobody has confirmed it yet: treat it as a draft until it is accepted or corrected. A field the sheet does not show comes back with value null; treat a path missing from fields the same way. A job’s values are the ones its template keeps, in its order: a field the template leaves out is never in fields.

Each entry of tables is one table on the sheet - { "path": "bom", "name": "Bill of Materials", "rows": [...] } - and each row is { "rowIndex", "cells" }, numbered from 0 in the order the drawing prints them, with one value per column under the column’s name. Every cell is a value like any other, with its own confidence, review state and box.

The general notes are the generalNotes table, a list with no columns: one row per note, in the order the drawing prints them, each note whole under value (generalNotes[0] is the first). A note is reviewed like any other value - accepted, corrected, or waiting for a person - but has no confidence and no box (both null): it is copied as printed rather than scored, and drawn on no single place on the sheet.

read_bom.sh
#!/usr/bin/env bash
set -euo pipefail
API=https://api.speccapture.com
AUTH="Authorization: Bearer $SPECCAPTURE_API_KEY"
JOB_ID=7c9e6679-7425-40de-944b-e07fc1f90ae7 # the jobId the submission answered with
SHEET_NUMBER=1 # which sheet: 1 is the first page
sheet=$(curl -sS --fail-with-body "$API/v1/extractions/$JOB_ID/sheets/$SHEET_NUMBER" \
-H "$AUTH") || { echo "$sheet" >&2; exit 1; }
jq -r '.tables[] as $table | if $table.path == "bom" then $table.rows[] as $row | ($row.cells as $cells | "Item \($cells.item.value): \($cells.qty.value // "?") x \($cells.partNumber.value // "(no part number)"), \($cells.description.value // "(no description)")") else empty end' <<<"$sheet"

Save as read_bom.sh, set SPECCAPTURE_API_KEY, and run: bash read_bom.sh. Needs curl; scripts also use bash and jq.

A workspace keeps each drawing for its retention period, limits.retentionDays in GET /v1/account, counted from the job’s completedAt: 30 days unless the workspace’s owner chose otherwise (0, 7, 30 or 90 days, on the dashboard’s workspace settings page). Within the hour after it ends, SpecCapture deletes the drawing: the uploaded file, its page images, and the box showing where each value was read.

  • Every box becomes null. The job and the sheet carry drawingPurgedAt, the time the drawing was deleted, so your software can tell a box that went with the drawing from a value that has no place on the sheet. Nothing else about the job changes: its status stays completed.
  • View links stop. A link made earlier stops working, and a new one is refused with 409 not_shareable from the last hour of the retention period on. A link’s expiresAt is never later than the drawing is kept.
  • The values stay: every value, its confidence, its review state and any correction, until the workspace is deleted, and so does the export, which no longer carries boxes.

With 0 days, a drawing is deleted as soon as its job has been read, its boxes within the hour, and no view link can be made. To keep the boxes longer than the drawing, store them when you read the sheet.

The values a sheet can carry, from the drawing template every sheet is read with today (drawing, version 1).

PathWhat it is
titleBlock.partNumberPart Number
titleBlock.drawingNumberDrawing Number
titleBlock.revisionRevision
titleBlock.titleTitle
titleBlock.materialSpecMaterial Specification
titleBlock.materialFormMaterial Form
titleBlock.stockSizeStock Size
titleBlock.finishFinish / Coating
titleBlock.platingSpecPlating Specification
titleBlock.surfaceFinishSurface Finish (roughness)
titleBlock.heatTreatHeat Treatment
titleBlock.scaleScale
titleBlock.unitsUnits · one of a set
titleBlock.sheetSizeSheet Size
titleBlock.sheetNumberSheet Number · whole number
titleBlock.sheetCountSheet Count · whole number
titleBlock.drawnByDrawn By
titleBlock.drawnDateDrawn Date · date
titleBlock.checkedByChecked By
titleBlock.checkedDateChecked Date · date
titleBlock.approvedByApproved By
titleBlock.approvedDateApproved Date · date
titleBlock.weightWeight
titleBlock.toleranceFractionsDefault Fraction Tolerance
titleBlock.toleranceDecimalsDefault Decimal Tolerance
titleBlock.toleranceOnePlaceDecimalsDefault One-Place Decimal Tolerance
titleBlock.toleranceTwoPlaceDecimalsDefault Two-Place Decimal Tolerance
titleBlock.toleranceThreePlaceDecimalsDefault Three-Place Decimal Tolerance
titleBlock.toleranceAnglesDefault Angle Tolerance
titleBlock.projectionAngleProjection Angle · one of a set
titleBlock.drawingStandardDrawing Standard
titleBlock.cageCodeCAGE Code
titleBlock.exportControlMarkingExport Control Marking

Measurements and counts SpecCapture works out from the drawing’s geometry and notes, rather than reads from one place on it.

PathWhat it is
assist.envelopeLengthEnvelope Length · dimension
assist.envelopeWidthEnvelope Width · dimension
assist.envelopeHeightEnvelope Height · dimension
assist.envelopeFormEnvelope Form · one of a set
assist.envelopeUnitsEnvelope Units · one of a set
assist.tightestToleranceTightest Tolerance on Print · dimension
assist.gdtCalloutCountGD&T Callout Count · whole number
assist.holeCountHole Count · whole number
assist.threadCalloutCountThread Callout Count · whole number
TablePathColumns (keys of cells)
Revision HistoryrevisionHistoryrev, description, date, approvedBy
Bill of Materialsbomitem, qty, partNumber, description, material
Hole TableholeTabletag, size, qty, depth
Application (next assembly / used on)applicationnextAssembly, usedOn
Dash Numbers (tabulated variants)dashNumbersdashNumber, description
General notesgeneralNotesvalue (one note a row, in order)