---
title: "Get an extraction's status, holding the request until it changes"
method: GET
path: "/extractions/{extraction_id}"
tags: ["Extractions"]
---

# Get an extraction's status, holding the request until it changes

`GET /extractions/{extraction_id}`

## Request

- Base URL: `https://api.invoicedataextraction.com/v1`
- URL: `https://api.invoicedataextraction.com/v1/extractions/{extraction_id}`
- Auth: HTTP bearer

The extraction's live status. With `wait`, the request is held until the extraction
leaves `processing` or the wait elapses, then answered with the ordinary payload, so a
handful of calls replaces a polling loop. Choose a wait shorter than your own client
or tool timeout; a response after the full wait is an ordinary `processing` response,
so call again. Without `wait`, leave at least 5 seconds between calls.

Every response is HTTP 200 with a top-level `status` of exactly one of `processing`,
`input_required`, `completed`, `failed`, `cancelled`; `success` is `true` for all of
them except `failed`. Branch on `status`, and treat a value you do not recognise as
non-terminal. The completed and cancelled responses carry the account's remaining
balance.

Rate limit: 120 requests per minute per API key; a held request counts as one.

## Path parameters

- `extraction_id` string, uuid, required

## Query parameters

- `wait` integer
- `scope` 'own' | 'team'

## Response `200`

The status, in the shape of the status it reports.

- union: The status response, one shape per `status`.
  - ExtractionProcessing
    - `success` true, required
    - `status` 'processing', required
    - `extraction_id` string, uuid, required
    - `progress` integer, required
  - ExtractionInputRequired: The extraction stopped to ask. Questions appear the moment they exist, and every open question of the extraction is listed together. If the questions are not all answered within about four minutes, the extraction pauses and waits, and the account owner is emailed that a task is waiting for an answer, with a second email before the deadline. If the questions are not all answered by `answer_by`, which is 40 hours after the files were uploaded, the extraction is cancelled with `cancellation_reason: unanswered` and the work done so far is charged. The extraction continues the moment every open question has an answer.
    - `success` true, required
    - `status` 'input_required', required
    - `extraction_id` string, uuid, required
    - `progress` integer, required
    - `answer_by` string, date-time, required
    - `questions` Question[], required
      - `question_id` string, required: Use it when answering.
      - `type` 'single_choice' | 'free_text', required: `single_choice` offers `choices`; answer with one, with words added if you like. `free_text` wants your own words, or the recommended approach. Words are accepted on every question, so an unrecognised type can still be answered with `text`.
      - `question` string, required
      - `example_from_documents` string: A real instance from the documents that the answer would change.
      - `scope` QuestionScope, required
        - `level` 'extraction', required: What the answer governs. `extraction` is the only value today: every document in the extraction, not only the one in the example. Treat a value you do not recognise as narrower than the extraction and read `applies_to`.
        - `applies_to` string, required: The scope in words, for whoever is answering.
      - `choices` QuestionChoice[], required: Empty for `free_text`.
        - `choice_id` string, required: A letter, `a` onwards.
        - `label` string, required
        - `cell_would_contain` string: The value this choice would put in the cell for the example, when known.
        - `recommended` true: Present on the one choice the extraction recommends.
      - `recommended_approach` string: On a `free_text` question, what the extraction does if you accept the recommendation.
      - `previous_answer_rejected` true: Present when an earlier answer to this question was refused. Answer differently.
  - ExtractionCompleted
    - `success` true, required
    - `status` 'completed', required
    - `extraction_id` string, uuid, required
    - `credits_deducted` integer, nullable, required: One credit per successfully processed page.
    - `credits_balance` integer, required: The account's total balance after this extraction was charged.
    - `credits_reserved` integer, required: Credits held by extractions still in progress; usable balance is `credits_balance` minus this.
    - `output_structure` 'per_invoice' | 'per_line_item', required: The resolved structure, also when `automatic` was submitted.
    - `output_expires_at` string, date-time, required: 90 days after submission; after it the output URLs are `null` and the rows and files are gone.
    - `pages` Pages, required: Which pages were processed and which failed; data from failed pages is missing from the output.
      - `successful_count` integer, required
      - `failed_count` integer, required
      - `successful` PageReference[], required
        - `file_name` string, required
        - `page` integer, required
      - `failed` PageReference[], required
        - `file_name` string, required
        - `page` integer, required
      - `failure_reasons` PageFailureReason[], required
        - `code` string, required
        - `message` string, required
        - `affected_pages` object[], required
          - `file_name` string, required
          - `pages` integer[], required
    - `ai_uncertainty_notes` UncertaintyNote[], required
      - `topic` string, required
      - `description` string, required
      - `suggested_prompt_additions` object[], required
        - `purpose` string, required
        - `instructions` string[], required
    - `review_needed` ReviewNeeded, required: Rows that need a human's check before the data is relied on. Check `count` first.
      - `count` integer, required
      - `items` ReviewNeededItem[], required
        - `message` string, required
        - `affected_fields` string[], required: Empty when the concern is about the row or document rather than particular fields.
        - `output_row_numbers` integer[], required: 1-based data row numbers, not counting the header row.
        - `source_references` string[], required
    - `output` OutputUrls, required: Signed URLs valid for 5 minutes; `null` when a format was not generated or the output has expired.
      - `xlsx_url` string, uri, nullable, required
      - `csv_url` string, uri, nullable, required
      - `json_url` string, uri, nullable, required
  - ExtractionFailed: HTTP 200 with `success: false`. Where the next step is to submit again, use a new `submission_id`.
    - `success` false, required
    - `status` 'failed', required
    - `extraction_id` string, uuid, required
    - `error` ExtractionFailureError, required
      - `code` 'INSUFFICIENT_CREDITS' | 'FILE_PAGE_LIMIT_EXCEEDED' | 'ENCRYPTED_FILE' | 'CONCURRENT_TASK_LIMIT' | 'NO_PAGES_FOUND' | 'VALIDATION_FAILED' | 'PROMPT_REJECTED' | 'PROMPT_UNCLEAR' | 'FILE_SIZE_LIMIT_EXCEEDED' | 'PROCESSING_FILE_SIZE_LIMIT_EXCEEDED' | 'SUBMISSION_STALLED' | 'INTERNAL_ERROR', required: Why an extraction failed. Retryable codes may succeed when submitted again with a new `submission_id`: `CONCURRENT_TASK_LIMIT` (as many extractions running as the account allows, 15 by default and more on request, counting those started in the web app), `SUBMISSION_STALLED`, `INTERNAL_ERROR`. The others need a change first: `INSUFFICIENT_CREDITS` (details: `credits_required`, `credits_balance`, `credits_reserved`), `FILE_PAGE_LIMIT_EXCEEDED` and `ENCRYPTED_FILE` (details: `file_names`), `NO_PAGES_FOUND`, `VALIDATION_FAILED`, `PROMPT_REJECTED`, `PROMPT_UNCLEAR`, `FILE_SIZE_LIMIT_EXCEEDED`, `PROCESSING_FILE_SIZE_LIMIT_EXCEEDED`.
      - `message` string, required
      - `retryable` boolean, required
      - `details` object, nullable, required
  - ExtractionCancelled: No output is produced; `credits_deducted` covers the work done before the extraction stopped.
    - `success` true, required
    - `status` 'cancelled', required
    - `extraction_id` string, uuid, required
    - `credits_deducted` integer, nullable, required
    - `cancellation_reason` 'user' | 'unanswered' | 'answers_rejected', required: `user`: cancelled from the dashboard or with `cancelExtraction`. `unanswered`: a question was not answered by `answer_by`. `answers_rejected`: three answers were refused.
    - `credits_balance` integer, required
    - `credits_reserved` integer, required

## Other responses

- `400`: `INVALID_INPUT`: the request does not match the contract; `details.issues` lists each problem with its `path`.
- `401`: `UNAUTHENTICATED`, `API_KEY_EXPIRED` or `API_KEY_REVOKED`.
- `403`: `FORBIDDEN`: `scope=team` from a caller who is not a team admin.
- `404`: `EXTRACTION_NOT_FOUND`: no extraction with this id within the caller's scope.
- `429`: `RATE_LIMITED`: wait `details.retry_after_seconds` (also the `Retry-After` header), then retry.
- `500`: `INTERNAL_ERROR`: retry after a short delay.

---

[API](https://skmtc.dev/invoicedataextraction/apis/invoice-data-extraction-api.md) · [All operations](https://skmtc.dev/invoicedataextraction/apis/invoice-data-extraction-api/llms.txt) · [OpenAPI document](https://skmtc.dev/invoicedataextraction/apis/invoice-data-extraction-api/revisions/16d920350483?raw)
