Ragextract for developers
Everything the application does, it does over this API: put documents into a workspace, ask a question per column, run it, and read back answers with the page each one was read from.
Two ways in
Both reach the same 53 endpoints. What differs is who writes the client.
What you can build
The API is the product without the grid on top. A client can ingest documents, define and run a table of questions over them, correct an answer, and read the citation behind every cell. That is enough to put extraction inside a pipeline that already exists — a deal tracker, an intake queue, a nightly job over a supplier folder — rather than asking anyone to open a second tool.
- Ingest. Upload a document, or hand over a URL to fetch. PDF, Office formats and images; over 100 MB goes in parts.
- Ask. A column is a prompt with one of eight output types, so what comes back is a date, a number, a category or a picture — not a paragraph you then have to parse.
- Check. Every answer carries the file, the page, the quote and a box on that page, plus a confidence score. Corrections are kept beside the extraction rather than replacing it.
- Retrieve. Semantic search across a workspace's pages, by text or by image.
What it is not: there is no endpoint for sharing a workspace, inviting someone, buying credits or changing a plan. Those are account acts and they stay in the app.
From nothing to a cited answer
The whole path, in one paste. Every call below has a page in the reference with its parameters and its failure modes.
export KEY="psk_live_…"
export API="https://api.ragextract.com/v2"
# 0 — what does this key reach?
curl $API/verify -H "x-api-key: $KEY"
# 1 — a workspace to work in
curl -X POST $API/workspaces -H "x-api-key: $KEY" \
-H "content-type: application/json" \
-d '{"name": "Vendor contracts"}'
# → data.id = wks_7Kq2mB4nR8vXpL3d
# 2 — put a document in it. This returns a JOB, not a finished file,
# and it is what spends credits: one per page.
curl -X POST $API/workspaces/wks_7Kq…/files -H "x-api-key: $KEY" \
-F "file=@acme-msa-2024.pdf"
# → data.id = dsj_L8vB2mQ6xR3kW9pZ
# 3 — poll until status is SUCCESS
curl $API/workspaces/wks_7Kq…/jobs/dsj_L8v… -H "x-api-key: $KEY"
# 4 — a table is a question per column and a document per row.
# All three of these are free; nothing is computed yet.
curl -X POST $API/workspaces/wks_7Kq…/tables -H "x-api-key: $KEY" \
-H "content-type: application/json" \
-d '{"name": "Vendor contracts"}'
# → data.id = rev_Qm5xC9bV3nK7sAeR
curl -X POST $API/workspaces/wks_7Kq…/tables/rev_Qm5…/columns \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{"name": "Governing law",
"prompt": "Which law governs this agreement?",
"outputType": "text_quote"}'
curl -X POST $API/workspaces/wks_7Kq…/tables/rev_Qm5…/rows \
-H "x-api-key: $KEY" -H "content-type: application/json" \
-d '{"subjectType": "file", "subjectId": "ds_M3xJ8pQ1vK5nB7wT"}'
# 5 — what would running it cost? Free to ask.
curl "$API/workspaces/wks_7Kq…/tables/rev_Qm5…/runs/preview" \
-H "x-api-key: $KEY"
# → { "cost": 4, "cells": 1, "skippedRowIds": [] }
# 6 — run it. THIS is the charged call.
curl -X POST $API/workspaces/wks_7Kq…/tables/rev_Qm5…/runs \
-H "x-api-key: $KEY" -H "content-type: application/json" -d '{}'
# 7 — read the answers, each with the page it came from
curl $API/workspaces/wks_7Kq…/tables/rev_Qm5…/cells -H "x-api-key: $KEY"
# → value, citations[{ fileId, page, quote, box }], confidenceThree things spend credits
Everything else — listing, reading, creating a table, adding columns and rows, pricing a run — is free. Credits are prepaid and there is no subscription.
- Ingest — 1 credit per page, once per document. Adding a column to a year-old table costs no more than adding it on day one, because the reading is already paid for.
- Extraction — the column's own rate per cell, from 4 credits, plus a surcharge on bundled rows. Charged per cell as each one succeeds, so a failed cell is not billed.
- Search — 40 credits per block of 100 searches. The one people do not expect, because a search feels like a read.
Run preview prices a run before you start it, using the same arithmetic the charge uses. Pricing has the rates in money.
Getting a key
Requests authenticate with a personal API key (psk_…) in the x-api-key header. Keys are created under Integrations → API keys in the Ragextract app’s settings, shown once, and stored hashed. A key never reaches more than the person who created it can, and scopes only ever narrow it further — Authentication has the model.
What is here
Getting started
Agent skillA SKILL.md to hand your coding agent, so it writes against this API rather than guessing at it.n8n nodeThe official community node: every resource here, as an operation in a workflow.API referenceThe base URL, what /v2 is, and the envelope every response arrives in.AuthenticationPersonal keys, the header they go in, what a key reaches, and the rate limits.ErrorsThe two error shapes, the status codes, and why 404 and 403 are not interchangeable.Core resources
WorkspacesListing what a key reaches, reading its level, creating and renaming one.FilesUploading a document, listing files, reading page images, deleting.Upload sessionsMultipart upload for anything over 100 MB: start, append, end, abort.JobsWatching an ingest through to Ready, and cancelling one.BundlesGrouping documents so a contract and its amendments answer as one row.Tables
TablesCreating a table, reading the whole grid in one call, archiving.ColumnsThe eight output types, the prompt, the credit rate, and column versions.RowsPointing a row at a file or a bundle, and removing one.CellsReading an answer with its citations, overriding it, and the audit underneath.RunsPricing a run before you start it, starting it, polling it, cancelling it.If you are writing JavaScript
There is an SDK, and for a JS or TypeScript caller it is the better door. @subworkflow/ragextract routes on your key’s prefix — a psk_ key reaches /v2 — so it is one import and a key:
npm i @subworkflow/ragextract # 0.2.0 or later
import { Ragextract } from '@subworkflow/ragextract';
const ragextract = new Ragextract({ apiKey: process.env.RAGEXTRACT_API_KEY });
const ws = ragextract.workspace('wks_7Kq2mB4nR8vXpL3d');
const file = await ws.files.upload(new URL('https://example.com/acme-msa-2024.pdf'));
const table = await ws.tables.create({ name: 'Vendor contracts' });
await ws.tables.addColumn(table.id, {
name: 'Governing law',
prompt: 'Which law governs this agreement?',
outputType: 'text_quote',
});
await ws.tables.addRow(table.id, { type: 'file', id: file.id });
const { cost } = await ws.tables.previewRun(table.id); // free to ask
const cells = await ws.tables.runAndWait(table.id); // this is the charged callIt wraps the two parts of this API that are genuinely awkward by hand: an upload switches to a multipart session above 100 MB without you choosing, and runAndWait() polls a run to completion, which every caller was otherwise writing for themselves. The workspace handle is there because every /v2 route nests under a workspace, and the alternative is a workspace id as the first argument of every call.
Pin ^0.2.0. 0.1.1 and earlier reach /v1 only — and could not be imported from Node at all, for want of a main field.
The reference below still describes the wire format rather than the SDK, deliberately: it is what a client in any language has to match, and it is where the parameters and failure modes live.
If you are using n8n
There is an official community node, n8n-nodes-ragextract, and from 0.2.0 it calls /v2 with the same personal key — tables, runs, bundles and search included. The n8n node covers installing it, the credential and what each operation does. 0.1.x reaches /v1 only, so an existing workflow needs the upgrade before anything on these pages works through it.
What is not here
- There is no Python client. Every sample carries a language switcher, but curl is the only tab on an endpoint page today. Everything here is reachable over plain HTTP from any language, which is what the reference documents.
- There are no webhooks. Ingest and extraction are asynchronous and you poll them — the job for a document, the run for a table. Both carry enough state for a progress bar.
- Reading your data from an LLM client is a different door. If the goal is to let Claude or an agent read workspaces, tables and answers, that is the MCP server — read-only, connected by signing in rather than by a key you hold, and gated per organisation. It adds no capability this API does not have; it removes the need to write a client.
Where else to look
The product documentation explains what these nouns mean — what a bundle is for, what makes an answer stale, how a correction is audited — screen by screen. A client is easier to write once those are settled, and this reference does not repeat them.