# Parsewise API — Instructions for Coding Agents

This document orients AI coding agents (Claude Code, Cursor, Codex,
Gemini, and similar) on how to drive the Parsewise platform through its
HTTP API.

When in doubt, fetch the OpenAPI schema — it is the authoritative
contract. Everything below is orientation and best-practice guidance on
top of that schema.

## What Parsewise is

Parsewise is a document intelligence platform. You upload source documents
into a project, define agents that describe what to extract from those
documents, launch extraction, and then read back structured results with
citations back to the source pages. The HTTP API exposes the same
workflow the product uses end-to-end, so anything a user can do in the
UI you can do programmatically.

## Core concepts

- **Project** — a container for documents, agents, and results. Scope one
  project per subject area (e.g. "Q4 leases").
- **Document** — a source file belonging to a project (PDF, Word,
  PowerPoint, Excel, or image). Parsewise parses and OCRs documents on
  upload.
- **Agent** — a reusable definition of *what* to extract and *how*. One
  agent produces one column of values across the project's documents.
- **Dimension** — an optional attachment to an agent that breaks its
  output into multiple values, one per dimension instance (e.g. one per
  clause, one per party, one per region).
- **Result** — the structured output of running agents against documents,
  including citations back to the source pages the values came from.

## Where the schema lives

The OpenAPI schema at `https://api.parsewise.ai/api/v1/schema/` is the
authoritative contract for request/response shapes, field names, and
enum values. It is public and does not require an API key. When anything
in this document disagrees with the schema, the schema wins. Fetch it
and consult it whenever you need exact shapes.

## Where to manage API keys

Create, rotate, and revoke API keys on the Developer page in the
Parsewise app at `https://app.parsewise.ai/developer`.


## Authentication

Every request to the v1 API must include your API key in the `X-API-Key`
header. Keys start with the `pw_live_` prefix and are scoped to a single
organisation. Treat keys like passwords: keep them in a secret manager,
never commit them, and never embed them in client-side code.


## The usual flow

End-to-end extraction is six steps. Each step produces the IDs the next
step needs, so do them in order. Fetch the schema for exact request and
response shapes — the description below covers the sequence and the why.

All requests carry the `X-API-Key` header, for example:

```
curl -H "X-API-Key: $PARSEWISE_API_KEY" "https://api.parsewise.ai/api/v1/projects/"
```

1. **Create a project.** Projects are containers for everything else.
   Scope one project per subject area.
2. **Upload source documents.** Uploads are multipart; Parsewise parses
   and OCRs them asynchronously. You don't need to wait for parsing to
   finish before launching — if parsing is still in flight when you
   launch, the run is queued and fires automatically once parsing
   completes. If no parsing is in flight, the launch pipeline itself
   parses any outstanding documents before extracting.
3. **Define agents.** Create one agent per column of data you want.
   Give each agent a short, descriptive name and an extraction task that
   specifies the value, its format, and any disambiguation rules — see
   the best practices below. By default an agent produces one value per
   project, aggregated across every document. If you need multiple
   values instead (one per clause, one per party, one per line item),
   attach a dimension to the agent.
4. **Launch extraction.** Launching starts the project's extraction
   pipeline. It takes no body and returns `202 Accepted` immediately;
   the actual work happens in the background.
5. **Poll for progress.** Each agent reports progress across four
   stages: parsing, extraction, web search, and resolution. A top-level
   `pipeline_running` flag on the status response is the easiest signal
   that the backend is still working; for a strict "all done and
   successful" check also confirm every agent's `extraction_status` is
   `Processed` — see the FAQ for why `pipeline_running=false` alone is
   not enough. Poll with exponential backoff (e.g. 2s, 4s, 8s, capped
   at ~30s); do not hammer the endpoint on a tight loop.
6. **Read results.** List the project's results, then fetch individual
   results to see their extracted values and the citations back to the
   source pages.

## Iterating after the first run

You rarely redo all six steps. Typical follow-ups:

- **New documents arrive** → upload them, then re-launch. The pipeline
  picks up the new files.
- **An agent is wrong** → update its definition, then re-launch.
  Re-launching is required: existing results were computed against the
  old definition and are stale until you run again.
- **A new column is needed** → create another agent, then re-launch.

## Constraints and gotchas

- **Launch is project-scoped.** There is no "only these documents" or
  "only this agent" option. Prove an agent out on a small test project
  before pointing it at thousands of production documents.
- **Don't stack concurrent launches.** A second launch issued while a
  run (or in-flight document parsing) is in progress is queued, not
  rejected — your new run is silently delayed behind the in-flight
  work. Poll status and wait until the pipeline is no longer running
  before launching again.
- **The schema is truth.** This document is orientation;
  `https://api.parsewise.ai/api/v1/schema/` is the source of truth for
  request and response shapes.


## How to name agents

Agent names show up everywhere — in the Agents page, in results columns,
in citations, in Navi answers — so treat them like column headers in a
spreadsheet.

- **Use a short noun phrase that describes the value, not the question.**
  Prefer `Counterparty name` over `Who is the counterparty?`; prefer
  `Notice period (days)` over `How many days is the notice period?`.
- **Include units or format hints when they disambiguate.** `Start date
  (ISO 8601)`, `Purchase price (USD)`, `Tenure (months)`.
- **Keep it under ~40 characters** so it renders cleanly in table headers.
- **Avoid project-specific jargon** that a new teammate would not
  recognise; the agent will often outlive the reason it was created.
- **One concept per agent.** If the name needs "and", split it into two
  agents so each value has its own column and its own citations.


## How to iterate on an agent

Treat agent design as an empirical loop, not a one-shot prompt.

1. **Start narrow.** Pick one well-understood document and write the
   minimal extraction task that works for it.
2. **Run the agent and read every citation.** The citation tells you
   whether the agent found the right *span*, which matters even when the
   extracted value happens to look correct.
3. **Look for failure modes, not wins.** Scan results where the agent
   returned empty, picked the wrong section, or produced a formatting
   variant you did not expect.
4. **Tighten the task description** to resolve the specific failure, then
   re-run. Avoid generic wording like "be accurate" — describe the
   concrete distinction the agent missed.
5. **Expand the document set** once the agent is stable on the seed
   document. New documents will surface new edge cases; repeat from step 3.
6. **Stop when additional iteration stops changing results.** More words
   in an extraction task rarely help past that point.


## Writing good extraction tasks

The extraction task is the prompt the agent uses to find and normalise a
value on each page.

- **Describe the value first, then where to find it.** "The effective
  date of the agreement, typically in the preamble or on the signature
  page" beats "Look at the first page".
- **Specify the output format explicitly.** Dates as ISO 8601, currencies
  as ISO 4217 codes, amounts as numbers without thousands separators,
  booleans as `true` / `false`.
- **Call out what *not* to extract.** "Ignore illustrative examples in
  appendices" or "Do not extract dates from the document metadata".
- **Give disambiguation rules for ambiguous documents.** "If multiple
  effective dates are present, prefer the one in the signature block
  over the one in the preamble."
- **Prefer citations-first reasoning.** "Return the clause verbatim in
  the citation, then normalise" pushes the agent to ground its answer.


## How many values an agent produces

By default an agent produces exactly one value per project, aggregating
evidence across every document. That is the right behaviour for
"single answer" fields where every document feeds into one canonical
value — a single counterparty name, a single effective date, a single
consolidated purchase price.

To get more than one value out of an agent, attach a **dimension**.
The agent then produces one value per dimension instance, yielding
one row per instance in the results. Dimensions come in two flavours:

- **Custom dimensions** you define and attach to specific agents
  (e.g. "Clause", "Party", "Region") — one value per instance.
- The **system `Document` dimension**, attached automatically to every
  agent in the project when the project has `per_document_mode` on —
  one value per uploaded document. Use this when every document is an
  independent subject rather than evidence for a shared answer (one
  contract per file, one report per file).

Rules of thumb:

- **Default to no dimension** when the whole project contributes to a
  single answer.
- **Add a custom dimension** when the value repeats per entity inside
  the document(s).
- **Enable `per_document_mode` at project creation** when each document
  is an independent subject and you want one row per file.
- **Keep dimensions stable across agents in the same project** when
  those agents describe the same underlying entity, so their results
  join cleanly on the same key.
- **Name the entity in the agent name** (`Lease obligations`,
  `Line items`) when a custom dimension is attached, so it is obvious
  at a glance that each row is an entity, not a project-level value.


## When to launch

Launching consumes compute and time, so batch it intentionally — but
not too parsimoniously:

- **Always re-launch after changing an agent.** Results are a snapshot
  taken at run time. Once you edit an agent's name, extraction task,
  value type, or dimensions, its existing results are stale. Never
  mutate an agent and then read results without re-launching — you
  will be reading data that does not match the current definition.
- **Always re-launch after uploading new documents.** Documents are
  not extracted against your agents until you launch. You don't need
  to wait for parsing — if parsing is still in flight, the launch is
  queued and fires automatically when parsing finishes; if it isn't,
  the launch pipeline parses outstanding documents itself.
- **Don't stack launches.** A launch issued while a run (or document
  parsing) is in progress is queued behind it. Poll status and wait
  for the current pipeline to finish, then launch.
- **Iterate on a small project first.** Launch is project-scoped —
  there is no "only these documents" option — so prove an agent out on
  a handful of documents before running it over thousands.


## FAQ

These are the questions the sections above and the OpenAPI schema do
not, on their own, fully answer.

### What do `per_document_mode` and `per_tag_mode` on a project actually do?

They are two mutually-exclusive "row shape" modes for the whole
project. When `per_document_mode` is on, a system-managed `Document`
dimension is attached to every agent in the project with one instance
per uploaded document, so result tables get one row per document.
`per_tag_mode` does the same thing but keyed by document tags rather
than filenames. Both default to off. Leave them off unless you
specifically want that row shape — for most analytical work, defining
your own dimensions on individual agents is more flexible.

### Can I turn `per_document_mode` on or off on an existing project via the API?

Set the mode when you create the project — not by PATCHing an existing
one. Flipping the flag through v1 `PATCH /projects/{id}/` does not run
the cleanup that has to accompany the change (wiping stale results,
attaching or removing the system `Document` dimension across every
agent), so you can end up with stale results and inconsistent agent
configuration. If you need to change the mode of a project that
already has data, recreate the project with the desired mode and
re-upload the documents — both steps are supported in v1.

### Can I create or list dimension templates via the v1 API?

No. The v1 agent payload accepts `dimension_template_id`, but v1
currently exposes no endpoint to create or list dimension templates.
Two practical consequences:

- If you only need row-per-document or row-per-tag output, enable
  `per_document_mode` or `per_tag_mode` at project creation instead.
  Those modes attach the system dimension for you without any template
  id, and are fully controllable from v1.
- If you truly need custom dimensions (e.g. one row per clause, per
  party, per region), that workflow is not yet available through v1.
  Track the roadmap or contact support if this is blocking you —
  submitting a made-up `dimension_template_id` will not create one.
  Unknown ids are silently skipped, so no error is returned and the
  dimension simply is not attached.

### The project status endpoint sometimes reports `parsing_state: stuck`. What does that mean?

It means at least one document has had a parsing run in flight for
over an hour. A background monitor will have already auto-retried
parsing once about 15 minutes in; `stuck` indicates that retry did
not clear the problem. There is no v1 endpoint to force another
retry. If the state persists, delete and re-upload the affected
documents (both supported in v1), or contact support.

### How do I tell, strictly, that a run is complete and succeeded?

Check two signals together. `pipeline_running=false` on
`agents/status/` means the backend is no longer actively processing —
but it also flips to false when validation fails or a run is cancelled,
so it alone does not prove success. For a strict "done and successful"
check, also fetch the agents list and confirm every agent reports
`extraction_status=Processed`. If some agents are still `Pending`
while `pipeline_running` is false, something went wrong during the
run — do not treat the results as final.

### What does `resolution_status: "Requires attention"` mean for me as a reader of results?

The resolver detected inconsistencies across the source documents and
decided it could not auto-resolve them, so it is flagging that a
human may want to review the inconsistency summary. The result still
carries a chosen value that you can read; the status is advisory. If
you are building a pipeline that only wants high-confidence values,
gate on `resolution_status == "Resolved"`; if you want every value the
agent produced, read values regardless of status.

### What do the four pipeline stages (`parsing`, `extraction`, `web_search`, `resolution`) actually do?

- **parsing** — OCR and text extraction from uploaded documents,
  page by page. Populates the text and images the rest of the
  pipeline reads.
- **extraction** — each agent finds candidate values on the relevant
  pages by running its extraction instructions against them.
- **web_search** — supplements those candidates with public web data,
  only for agents that have web search enabled.
- **resolution** — consolidates the per-page, per-source candidates
  into a single final value per result cell, checking for and
  flagging inconsistencies across sources.
