ZIP Files
Upload a ZIP archive containing multiple documents in a single call. Each file inside the ZIP is extracted and processed as an independent document.
Each file inside the ZIP becomes a separate document — they can be of different types. Bundle a batch from an external system into one ZIP and send a single request. You can also combine a ZIP upload with the Classifier to detect each type automatically.
Step 1 — Upload the ZIP
Upload the ZIP exactly like any other file — same endpoint, same info field. Invofox detects the MIME type automatically.
The upload response does not include documentIds — Invofox doesn’t know how many files the ZIP contains until it’s extracted. Save the importId instead:
Any clientData you include in the info field is propagated to every document extracted from the ZIP — all of them share the exact same clientData.
Step 2 — Get the results
Retrieve the documentIds once processing is done. Webhooks are the recommended approach; you can also poll the import.
Listen for import.processed to know when the whole ZIP is done, then fetch each document. No polling.
Check the import status until processed, then collect documentIds from the extracted files and fetch each one.
Option A · Webhooks (recommended for production)
A document.processed event fires for each file as it finishes, carrying the full extracted document in its data field — same payload format as Step 3 of Integrating Invofox.
Because you don’t know upfront how many files a ZIP contains, you can’t rely on counting document.processed events to know when the ZIP is fully done. Instead, listen for import.processed — this event fires once, after every file in the ZIP has been processed. Iterate data.files[] for the documentIds (the ZIP’s own entry has an empty documentIds — skip it).
Option B · Poll the import
Poll GET /v1/ingest/imports/{importId} until status is "processed". While processing, status is "processing" and the documents counter increases as each file is extracted — don’t rely on it until status is "processed". The response holds one entry for the ZIP itself (compressed: true, documentIds: []) plus one entry per extracted file. The real documentIds are on those child entries — iterate over all files[] and skip any with compressed: true.
Each extracted file keeps its original name inside the archive (files[].filename) — unlike the Splitter, which renames its outputs to split_n.pdf. Collect every documentId across the child entries.
Fetch each document
For each documentId, call GET /documents/{documentId} — same response format as the standard flow. Documents extracted from a ZIP carry import.fromZip: true and import.filename set to the file’s name inside the archive:
A file inside the ZIP can fail on its own (unsupported format, corrupt, or password-protected) while the import as a whole still reaches status: "processed" — so always check each child’s status/error. See Rejected files for how to handle the file.rejected webhook.