curl.
All requests go to https://api-v2.getomni.ai and authenticate with your
workspace API key in the x-api-key header. Export both once so the examples
run as-is:
Before you start
Three things to have in place before writing integration code:- An API key. Generate one in workspace settings.
Keys are scoped to your workspace: every lead, document, spread, and artifact
in this guide is only visible to keys from the same workspace. Requests
without a valid
x-api-keyheader return401. - Leads and documents flowing into Omni. A spread always runs against a lead’s documents, so decide where those come from first. If you already create leads via the API or a CRM sync and collect documents through Omni, you’re set — skip straight to step 4. If not, steps 2 and 3 show the minimal API calls to create a lead and attach files.
- A webhook endpoint (recommended). To be notified when spreads finish
rather than polling, you’ll need a public HTTPS endpoint that accepts POST
requests and responds
2xxwithin 5 seconds. Step 6 covers registering it and authenticating deliveries.
1. Overview
Financial spreading takes a set of financial documents for one business — tax returns, income statements, balance sheets — and turns them into a standardized, multi-period spread. Omni classifies each document, extracts the line items, consolidates everything onto a fixed underwriting template, and computes the derived statements (income statement, balance sheet, cash flow) plus summary ratios. A completed spread produces two downloadable artifacts:
A spread runs in the background and typically takes a few minutes, driven
mostly by document count and page count. You start a run, then either poll its
status or wait for a webhook. Spreads are always scoped to a lead — the
business you are underwriting — so the flow is: create a lead, upload its
documents, start the spread.
2. Create a lead
A lead represents the business you are spreading. If you already create leads through the API or a CRM sync, reuse the existing lead’s id and skip to step 3.201 response wraps the created lead under lead; keep lead.id:
3. Upload financial documents
Attach the business’s financial documents to the lead. You can either upload the files directly (multipart) or pass a list of URLs Omni will fetch. Only PDF documents are spreadable — other file types are stored on the lead but ignored by the spread. Upload local files (multipart form-data):201 response lists the created documents with their ids:
documents array, in webhook payloads, and as the documentIds
filter when starting a spread.
4. Start the spread
Start a run for the lead with Create Spread. By default it spreads every PDF document on the lead; passdocumentIds to
restrict it to a subset.
Request body
Response — 201 Created
The run is created and queued immediately; the response returns before any
processing happens.
Errors
5. Track progress
Poll the run with Get Spread for its status, per-document progress, and (once finished) its artifacts.Run lifecycle
A run’sstatus is IN_PROGRESS from the moment it’s created, then resolves
to COMPLETE or FAILED.
Each input document also has its own status: PROCESSING while the run works
on it, ending at EXTRACTED (financial data captured), SKIPPED (nothing
spreadable found), or FAILED (that document couldn’t be processed). A single
failed document doesn’t necessarily fail the
whole run — the other documents still spread. The run resolves to FAILED when
it can’t produce a spread — most often because every document failed to process
or none of them contains a recognizable financial statement, though a
processing stage can also fail outright. In every case error carries a short,
human-readable reason (for example, “No financial statements were found in the
uploaded documents…”).
Poll until status is COMPLETE or FAILED. A COMPLETE status always
includes the artifacts array with the report and spreadsheet.
6. Webhooks (recommended)
Polling works, but webhooks let you react the moment a spread finishes without a poll loop. Subscribe once, then receive an HTTP POST for each event. Register a subscription for the three spread events with Create Webhook (or do the same in the Omni app under Settings → Webhooks):headers is how you authenticate them: any
headers you set on the subscription are sent with every delivery. Set a secret
header here and reject requests to your endpoint that don’t carry it.
Events
Every delivery has the same envelope.
actor is always null for spread
events; data carries the run, with documents keyed by the same document ids
as the rest of the API:
spread.started carries the same shape at status: "IN_PROGRESS" with no
artifacts. spread.failed omits artifacts and adds error, a short,
human-readable reason for the failure.
Things to know
spread.startedfires for every run, not just yours. If a teammate starts a spread from the Omni app, your endpoint still receivesspread.startedwith the newspreadId— record the id, then poll or await the terminal event.- Respond within 5 seconds. A delivery that doesn’t get a
2xxwithin 5 seconds counts as failed and is retried with backoff (roughly 1, 2, 5, 10, then 20 minutes between attempts) for up to 6 total attempts, after which it’s marked failed. Acknowledge fast and do heavy work (like downloading artifacts) asynchronously. - Handle repeat deliveries. The same event can arrive more than once for a
spread: a retry repeats an identical payload, and a regeneration (step 8)
legitimately re-emits
spread.completedwith new artifact ids. Don’t drop repeats by event name alone — treat each delivery as the run’s latest state, keyed bydata.spreadId, and process it idempotently. - Test leads don’t fire. Spreads on a test lead emit no webhooks.
7. Download the artifacts
When a run isCOMPLETE, its artifacts array (from the status poll or the
spread.completed webhook) holds the ids you download. A REPORT downloads as
a PDF and a SPREADSHEET as an xlsx workbook.
Fetch metadata with Get Artifact
(optional — gives you the content type and a suggested filename):
-o to
save the file:
artifacts
array:
8. Regenerate a spread
Regenerate Spread rebuilds a finished run from its already-extracted data: the documents are not re-processed; only the consolidation and report run again. Any analyst adjustments recorded on the run inside Omni are applied, so regenerating is how an integration picks up corrections made in the app.202 response returns the run back at IN_PROGRESS; on completion the run
has new artifact ids. A regenerated run re-emits spread.started and
spread.completed — the second completion carries the new artifact ids, which
is why deliveries are processed as state updates rather than dropped as
duplicates.
Regenerating a run that is still in flight returns 409, and an unknown spread
id returns 404.
9. End-to-end script
This bash script chains the whole loop: create a lead, upload a PDF, start the spread, poll until it finishes, then download both artifacts. It needscurl
and jq.