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

Following a job

A job’s status says where the whole file is:

status What it means
queued Accepted and paid for; waiting to be split into its sheets.
splitting Being split into its sheets.
extracting Its sheets are being read, each on its own.
completed Every sheet has finished: read, or failed and refunded.
failed The file could not be split into sheets, and everything it held was refunded. failureReason says why, in words for a person.

The job’s templateId and templateVersion name the template its values are kept with - drawing and 1 for the standard template - and templateName what the workspace calls it (null for drawing); see Templates.

Each entry of the job’s sheets has a status of its own - queued, running, completed, or failed (the sheet could not be read, and its credits were refunded) - and, once read, its reviewState and the resultUrl its values are at. progress counts the sheets completed, failed and needing review, and credits says what the job has reserved, spent, refunded and still holds.

GET /v1/extractions/{jobId} until its status is completed or failed:

wait.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
while true; do
job=$(curl -sS --fail-with-body "$API/v1/extractions/$JOB_ID" \
-H "$AUTH") || { echo "$job" >&2; exit 1; }
jq -r '"\(.status): \(.progress.sheetsCompleted) of \(.sheetCount) sheets read"' <<<"$job"
if [[ "$(jq -r '.status' <<<"$job")" =~ ^(completed|failed)$ ]]; then break; fi
sleep 5
done
jq -r '"\(.progress.sheetsNeedingReview) sheets need a person to look; \(.credits.refunded) credits refunded"' <<<"$job"

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

Every 5 seconds is plenty: a sheet takes tens of seconds, and every request counts against the key’s rate limit. There is no need to wait for the whole file: a sheet whose own status is completed can be read at its resultUrl straight away, while the rest are still being read.

To find jobs you did not keep the id of - a drawing uploaded in the dashboard, or everything finished since you last looked - list them: GET /v1/extractions answers the workspace’s jobs newest first, a page at a time (Lists and paging), each as GET /v1/extractions/{jobId} answers it but without its sheets (progress says how they stand, and url is where the job is). status keeps only jobs in one status, and fileName only those whose file name contains it, in any case: ?status=completed&createdAfter=2026-10-14T00:00:00Z is every job finished since that day began.

Instead of asking, add a webhook endpoint (POST /v1/webhooks, or Webhooks in the dashboard), and SpecCapture posts a signed event to it when each job finishes: extraction.completed once every sheet has finished, or extraction.failed when the file could not be split. The event carries the job exactly as GET /v1/extractions/{jobId} returns it, and links to its exports. See Webhooks.

Now and then reading pauses for a while: for every workspace, or for one workspace that has reached its daily limit (a safety cap on how much each workspace can have read in one day), until 00:00 UTC. Nothing is lost and nothing needs doing. Submissions are still accepted and their credits reserved as usual; a job waits unfinished (queued, or extracting with its sheets queued), its credits stay held and none is spent on a sheet not yet read; when reading resumes every sheet is read automatically, and the job finishes and its webhook is sent as usual. Do not submit the file again: a new submission is a new job, and reserves its own credits. The dashboard shows a notice on every page while a pause lasts, with the time it ends when that is known.