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/extractionswith asubmission_idthat already belongs to an extraction returns that extraction when the request is the same one sent again: the sameupload_session_id,file_ids,prompt,output_structureandoptions. Any other request under thatsubmission_idis now refused with409 SUBMISSION_ID_ALREADY_USED, where before it was answered with the existing extraction. The error'sdetailscarry the existingextraction_idand the request fields that differ. Use a newsubmission_idfor each extraction.- The SDKs raise it as they raise every API error, and the MCP server's
run_extractionandsubmit_extractionreturn it. - The message of an extraction that failed with
INSUFFICIENT_CREDITSsays to submit again with a newsubmission_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 ownextraction_id, for a signed-in person to read the rows and download the files.- The MCP server's completed status and
get_output_download_urlcarry that address asdashboard_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/importuploads 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'simport_attached_filestool calls it.- The
INSUFFICIENT_CREDITSmessages 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 inaffected_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.00is"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%is20), 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 get0.2; a fraction is now exact (14.3%is0.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
nullwhere a value is missing gets an empty cell, andnullin the JSON output withoptions.json_typed_valueson, 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_FILEnow 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/mcpgives 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
/agentsand/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
/changelogand/changelog.md.
2026-09-12: Every question says its scope; SDKs 0.6.1
- Every question on an
input_requiredstatus carriesscope:level(extractiontoday) andapplies_toin 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 intext. - 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
scopeon 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_questionson submit lets the extraction stop and ask when the documents leave something unsettled. The status is theninput_required, from the moment the questions exist, with every open question and theanswer_bydeadline.POST /v1/extractions/{extraction_id}/answerstakes a choice, a choice with words beside it, words alone, oraccept_recommended, and answers with the extraction's status. A repeated post after the extraction has moved on is not an error.input_requiredin the list filter and on the details record, which also carries the questions.- Two new cancellation reasons:
unanswered(nobody answered byanswer_by) andanswers_rejected(three refused answers). - SDKs 0.6.0:
extract(...)takesask_questionsand anon_questionshandler that answers in your code; without the handler it returns the waiting status for you to answer withanswerQuestions(...)/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
waitonGET /v1/extractions/{extraction_id}(1 to 45 seconds) holds the request until the extraction leavesprocessing, 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_balanceandcredits_reservedon the completed and cancelled status responses.POST /v1/extractions/{extraction_id}/cancelstops an extraction that is queued or processing; cancelled responses carrycancellation_reason, andcancelledjoins the list filter.- Per-extraction output options on submit:
output_language,review_needed_fill_color,affected_field_fill_colorandsend_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_LIMITEDcarriesdetails.retry_after_secondsbeside theRetry-Afterheader, andVALIDATION_FAILEDis 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 onextract(...)andsubmitExtraction(...)/submit_extraction(...), and retries hardened for non-JSON gateway responses.
2026-07-06: API host hardening and docs links
- Requests to paths outside
/v1/onapi.invoicedataextraction.comreturn the standard JSON error envelope instead of plain text. invoicedataextraction.com/docsredirects to the API reference.
2026-07-03: SDKs 0.4.0
- The Node.js and Python SDKs send
X-SDK-NameandX-SDK-Versionheaders naming the client. Any client may send them.
2026-06-21: SDKs 0.3.0
- Review Needed warnings, the
cancelledstatus and page failure reasons in the SDKs' responses, matching the API.