Changelog

What changed in the API and the SDKs, newest first, and the versioning promise.

This page as Markdown: /docs/changelog.md

Invoice Data Extraction API and SDK changelog

Versioning. The API is versioned by URL path (/v1). Backward-compatible additions ship without a version change and are announced here. Breaking changes, if ever needed, ship as a new version path with at least 6 months of dual operation.

2026-10-10: A submission_id that is already in use

  • POST /v1/extractions with a submission_id that already belongs to an extraction returns that extraction when the request is the same one sent again: the same upload_session_id, file_ids, prompt, output_structure and options. Any other request under that submission_id is now refused with 409 SUBMISSION_ID_ALREADY_USED, where before it was answered with the existing extraction. The error's details carry the existing extraction_id and the request fields that differ. Use a new submission_id for each extraction.
  • The SDKs raise it as they raise every API error, and the MCP server's run_extraction and submit_extraction return it.
  • The message of an extraction that failed with INSUFFICIENT_CREDITS says to submit again with a new submission_id: the same request under the same one returns the failed extraction.

2026-10-09: The extraction's page in the dashboard

  • https://invoicedataextraction.com/dashboard/results/{extraction_id} opens a completed extraction in the dashboard, with the API's own extraction_id, for a signed-in person to read the rows and download the files.
  • The MCP server's completed status and get_output_download_url carry that address as dashboard_url, so an assistant gives its owner the page and the five-minute download address as links, or saves the file for them where it can.

2026-10-07: Numbers in a text column

  • Unless your prompt says how, when a column is text because you asked for a symbol or unit with a number or for several values in one cell, each kind of number in it comes out in one form for the whole column, with no value rounded: an amount with its currency symbol or code, or a rate with its percent sign, with a decimal point, no thousands separators and one number of decimal places; any other number, such as a quantity with its unit or line values joined in one cell, in the form your documents use for it.

2026-10-02: Connecting from ChatGPT and Claude, and files attached in a conversation

  • The MCP server accepts sign-in: an assistant that supports it, such as ChatGPT or Claude, opens the Invoice Data Extraction sign-in page when it connects, and the owner signs in or creates an account and approves it, with no API key to paste. Harnesses that send an API key connect as before.
  • POST /v1/uploads/import uploads the files attached in an assistant's conversation from the download links the assistant gives, creating the upload session and completing every file in one call; the MCP server's import_attached_files tool calls it.
  • The INSUFFICIENT_CREDITS messages say where credits are bought and link to the plans and prices.

2026-10-02: How numbers are written

  • A value that does not read as a number, which every file holds as the extracted text, now puts its row in review_needed, with the column in affected_fields, and a note in the row's Review Needed column.
  • A missing-value placeholder that is itself a number is written as the numbers of that column are (0.00 is "0,00" where your prompt asks for a decimal comma).

2026-09-28: The value your prompt asks for, in every file

  • Every output file holds the same value in each cell. In the CSV, and in the JSON output without options.json_typed_values, amounts, quantities and rates keep their decimal places ("18.00"), and are written with the decimal and thousands separators your prompt asks for ("1.234,50"), or as plain digits with a decimal point when it does not say.
  • An amount asked for with its currency symbol or code carries it in every file, as a string, written the same way whatever each document prints: the symbol directly before the number and a code before it with a space (£1234.50, EUR 1234.50), the number as in the CSV. A rate asked for with its percent sign is written the same way, the sign directly after the number (19%).
  • A rate is the number the document prints, in every file (20% is 20), where before a prompt that did not say how to write it could get the fraction (0.2). Ask for the fraction, or for a spreadsheet percentage, to get 0.2; a fraction is now exact (14.3% is 0.143).

2026-09-28: Prompts up to 5,000 characters

  • A prompt written as a sentence can be up to 5,000 characters, up from 2,500, through the API, the SDKs and the MCP server alike.

2026-09-22: A missing value asked for as null

  • A prompt that says to use null where a value is missing gets an empty cell, and null in the JSON output with options.json_typed_values on, instead of the word in the cell.

2026-09-21: Protected PDFs that open without a password

  • A PDF that restricts printing, copying or editing but opens without a password is processed like any other file. ENCRYPTED_FILE now applies only to a file that needs a password to open, and its message says so.

2026-09-15: Source on GitHub; SDKs 0.6.2

  • The SDKs' source, the OpenAPI contract, the MCP server's code and the skill are public on GitHub at github.com/invoicedataextraction: sdk-node, sdk-python, api, mcp and skills, each with issues open for bug reports.
  • SDKs 0.6.2: the npm and PyPI packages name their repositories, and the Node.js package carries its licence file. No change in behaviour.

2026-09-13: The MCP server

  • A remote MCP server at https://mcp.invoicedataextraction.com/mcp gives an agent in Claude Code, Codex, Cursor, Hermes, OpenClaw or Gemini CLI the whole extraction loop as tools, with the API key as a bearer header: upload, submit, wait, answer questions, read the rows, download a file, list, cancel, and one tool that submits and waits in a single call. Through it, typed values and questions are on unless the call says otherwise. The setting for each harness and the tools: /docs/mcp, Markdown at /docs/mcp.md.

2026-09-12: The docs under one address, and an entry page for the API and for agents

  • /api is the entry page for the API and for agents: why to run extraction through your own agent rather than have it read the documents, the skill to give it, and one block per path with its docs.
  • The docs live under /docs: the REST API reference, the Node.js and Python SDK docs, the agent guide and this changelog, each with its Markdown twin at the same address plus .md. The previous page addresses redirect, and the previous Markdown addresses (/api.md, /sdk/node.md, /sdk/python.md, /agents.md, /changelog.md) keep serving the same documents.

2026-09-12: Machine-readable docs, the agent guide and the skill

  • The API contract as an OpenAPI 3.1 specification at /openapi.yaml and /openapi.json.
  • The docs as Markdown: /api.md, /sdk/node.md and /sdk/python.md, each the whole reference for its path; /llms.txt indexes them.
  • The agent guide at /agents and /agents.md: when to hand documents to this service, the whole loop including answering questions, and the limits in one place.
  • A skill for coding agents and assistants, discoverable from /.well-known/agent-skills/index.json: npx skills add https://invoicedataextraction.com.
  • /pricing.md: the offer and the price table as plain text.
  • This changelog, at /changelog and /changelog.md.

2026-09-12: Every question says its scope; SDKs 0.6.1

  • Every question on an input_required status carries scope: level (extraction today) and applies_to in words. An answer governs every document in the extraction, not only the one in the question's example; where the right answer differs by document type, say so in text.
  • The reference describes what a refused answer is: one given in bad faith, screened out and asked again with previous_answer_rejected. A vague or undecided answer is applied, and the matter may be asked again as a new question.
  • SDKs 0.6.1: the Node.js type declarations carry scope on every question. The Python package is at 0.6.1 too, with no change in behaviour.

2026-09-11: The extraction can ask you questions; SDKs 0.6.0

  • options.ask_questions on submit lets the extraction stop and ask when the documents leave something unsettled. The status is then input_required, from the moment the questions exist, with every open question and the answer_by deadline.
  • POST /v1/extractions/{extraction_id}/answers takes a choice, a choice with words beside it, words alone, or accept_recommended, and answers with the extraction's status. A repeated post after the extraction has moved on is not an error.
  • input_required in the list filter and on the details record, which also carries the questions.
  • Two new cancellation reasons: unanswered (nobody answered by answer_by) and answers_rejected (three refused answers).
  • SDKs 0.6.0: extract(...) takes ask_questions and an on_questions handler that answers in your code; without the handler it returns the waiting status for you to answer with answerQuestions(...) / answer_questions(...).
  • An SDK at 0.5.0 or earlier that polls an extraction submitted from the web app with questions on now meets input_required, a status its wait loop does not know, and stops with an error after about five minutes where it used to keep polling. Update to 0.6.0 or later.

2026-09-10: Held status requests, rows as JSON, cancel, output options, typed values; SDKs 0.5.0

  • wait on GET /v1/extractions/{extraction_id} (1 to 45 seconds) holds the request until the extraction leaves processing, so a handful of calls replaces a polling loop.
  • GET /v1/extractions/{extraction_id}/results: the extracted rows as JSON, in pages of up to 1,000, with the Review Needed items for each page alongside.
  • credits_balance and credits_reserved on the completed and cancelled status responses.
  • POST /v1/extractions/{extraction_id}/cancel stops an extraction that is queued or processing; cancelled responses carry cancellation_reason, and cancelled joins the list filter.
  • Per-extraction output options on submit: output_language, review_needed_fill_color, affected_field_fill_color and send_completion_email, each defaulting to the account's preferences.
  • options.json_typed_values: native JSON types in the JSON output file and the results endpoint. Recommended for a new integration that reads the rows; the default stays strings.
  • Every error message says what happened and what to do next. RATE_LIMITED carries details.retry_after_seconds beside the Retry-After header, and VALIDATION_FAILED is a failure code of its own.
  • SDKs 0.5.0: the held status check, getResults(...) / get_results(...) and the row iterators, cancelExtraction(...) / cancel_extraction(...), the output options on extract(...) and submitExtraction(...) / submit_extraction(...), and retries hardened for non-JSON gateway responses.
  • Requests to paths outside /v1/ on api.invoicedataextraction.com return the standard JSON error envelope instead of plain text.
  • invoicedataextraction.com/docs redirects to the API reference.

2026-07-03: SDKs 0.4.0

  • The Node.js and Python SDKs send X-SDK-Name and X-SDK-Version headers naming the client. Any client may send them.

2026-06-21: SDKs 0.3.0

  • Review Needed warnings, the cancelled status and page failure reasons in the SDKs' responses, matching the API.