API Reference

Harness API — v1  ·  Base: https://harness.jheel.io

The jheel.io Harness API provides an asynchronous document extraction workflow, enterprise RAG queries, and autonomous agent management — all through a consistent, authenticated REST interface.

Workflow overview

For document extraction, the standard flow is:

  1. Create a session — a container for one or more related documents.
  2. Upload one or more documents to the session.
  3. Poll the document endpoint until ExtractedJSON is populated or ErrorMessage is non-empty.
Document processing is asynchronous. Always poll for results — do not assume ExtractedJSON will be available immediately after upload.

Authentication

All endpoints require an API key passed in the request header. API keys are issued per account and are prefixed jh_live_ for production.

Header

X-API-KEY: jh_live_your_key_here

Include this header on every request. Requests without a valid key return 401 Unauthorized.

Base URL

https://harness.jheel.io

All endpoints are relative to this base URL. HTTPS only.

Create Session

Creates a new extraction session. A session acts as a container for one or more uploaded documents. Use a meaningful ClientID for your own reference — it is returned in all session responses.

POST /harness/session/

Headers

Accept: application/json
Content-Type: application/json
X-API-KEY: <api-key>

Request body

Field Type Required Description
ClientID string required Your own reference identifier for this session. Returned as-is in all responses.

Example request

POST https://harness.jheel.io/harness/session/
Content-Type: application/json
X-API-KEY: jh_live_xk29fmz...

{
  "ClientID": "q4-audit-2026"
}

Example response

{
  "ID": 198,
  "TenantID": 1,
  "ClientID": "q4-audit-2026",
  "Data": null,
  "Created": "2026-06-14T09:00:00.000000Z",
  "Updated": "2026-06-14T09:00:00.000000Z"
}

Python

import requests

BASE_URL = "https://harness.jheel.io"
API_KEY  = "jh_live_xk29fmz..."

response = requests.post(
    f"{BASE_URL}/harness/session/",
    headers={
        "Accept":       "application/json",
        "Content-Type": "application/json",
        "X-API-KEY":    API_KEY,
    },
    json={"ClientID": "q4-audit-2026"},
)
response.raise_for_status()

session = response.json()
session_id = session["ID"]   # → 198

Upload Document

Uploads a document to an existing session. A session can hold multiple documents. Extraction begins immediately after upload and runs asynchronously — poll the status endpoint to retrieve results.

POST /harness/session/{sessionID}/document/

Headers

Accept: application/json
X-API-KEY: <api-key>
Do not set Content-Type manually when using multipart form uploads in Python's requests library. Let the library set it — it includes the required boundary parameter automatically.

Multipart form fields

Field Type Required Description
type string required Document type. Accepted values: invoice, bank-statement, healthcare-form, brokerage-report, purchase-order
file file required The document file. Accepted formats: PDF, DOCX, XLSX, JPG, PNG.

Example request

POST https://harness.jheel.io/harness/session/198/document/
Accept: application/json
X-API-KEY: jh_live_xk29fmz...
Content-Type: multipart/form-data; boundary=...

type=invoice
file=@q4-invoice.pdf

Example response

{
  "ID": 47,
  "SessionID": 198,
  "Document": "invoice__47.pdf",
  "DocumentName": "q4-invoice.pdf",
  "MimeType": "application/pdf",
  "ExtractedJSON": null,
  "CostUSD": 0,
  "ErrorMessage": "",
  "ResponseTimeMs": 0,
  "Type": "invoice",
  "Created": "2026-06-14T09:01:00.000000Z",
  "Updated": "2026-06-14T09:01:00.000000Z"
}

Python

import requests

session_id = 198

response = requests.post(
    f"{BASE_URL}/harness/session/{session_id}/document/",
    headers={
        "Accept":    "application/json",
        "X-API-KEY": API_KEY,
    },
    data={"type": "invoice"},
    files={"file": ("q4-invoice.pdf", open("q4-invoice.pdf", "rb"), "application/pdf")},
)
response.raise_for_status()

document = response.json()
document_id = document["ID"]   # → 47

Get Document Status

Retrieves the current processing status and extracted JSON for a document. Use this endpoint to poll until extraction completes.

GET /harness/session/{sessionID}/document/{documentID}/

Headers

Accept: application/json
X-API-KEY: <api-key>

Example request

GET https://harness.jheel.io/harness/session/198/document/47/
Accept: application/json
X-API-KEY: jh_live_xk29fmz...

Example response — extraction complete

{
  "ID": 47,
  "SessionID": 198,
  "Document": "invoice__47.pdf",
  "DocumentName": "q4-invoice.pdf",
  "MimeType": "application/pdf",
  "CostUSD": 0.002346,
  "ResponseTimeMs": 5302,
  "Type": "invoice",
  "ErrorMessage": "",
  "ExtractedJSON": {
    "VendorName": "Meridian Supply Co.",
    "InvoiceDate": "2026-06-01",
    "DueDate": "2026-07-01",
    "InvoiceNumber": "INV-4892",
    "TotalAmount": 12450.00,
    "TaxAmount": 1128.00,
    "LineItems": [
      {
        "Description": "Professional Services — Q2",
        "Quantity": 1,
        "UnitPrice": 12450.00,
        "Total": 12450.00
      }
    ]
  },
  "Created": "2026-06-14T09:01:00.000000Z",
  "Updated": "2026-06-14T09:01:05.000000Z"
}

Response fields

Field Type Description
ExtractedJSON object | null Null while processing. Populated with structured data on completion.
ErrorMessage string Empty string on success. Contains failure detail if extraction failed.
CostUSD float Processing cost for this document in USD.
ResponseTimeMs integer Extraction processing time in milliseconds.

Polling Guide

Extraction is asynchronous. After uploading a document, poll the status endpoint at a regular interval until one of two terminal states is reached.

States

State ExtractedJSON ErrorMessage
Processing null "" (empty)
Complete object "" (empty)
Failed null non-empty string

Python polling example

import time
import requests

def poll_document(session_id: int, document_id: int) -> dict:
    url = f"{BASE_URL}/harness/session/{session_id}/document/{document_id}/"
    headers = {"Accept": "application/json", "X-API-KEY": API_KEY}

    while True:
        resp = requests.get(url, headers=headers)
        resp.raise_for_status()
        data = resp.json()

        if data.get("ErrorMessage"):
            raise RuntimeError(f"Extraction failed: {data['ErrorMessage']}")

        if data.get("ExtractedJSON") is not None:
            return data["ExtractedJSON"]

        print("Processing… retrying in 2s")
        time.sleep(2)


result = poll_document(session_id=198, document_id=47)
print(result["VendorName"])   # → "Meridian Supply Co."
A polling interval of 2–5 seconds is recommended. Most documents complete within 3–8 seconds; complex multi-page documents may take longer.

RAG — Query Documents

Once documents have been processed within a session, they form a queryable knowledge base. Submit a natural-language question against the session's document corpus and receive a structured answer with source attribution and confidence scoring.

POST /harness/rag/query/

Headers

Accept: application/json
Content-Type: application/json
X-API-KEY: <api-key>

Request body

Field Type Required Description
session_id integer required The session ID whose documents will be queried.
q string required Natural-language question. Query in plain English — no special syntax required.

Example request

POST https://harness.jheel.io/harness/rag/query/
Content-Type: application/json
X-API-KEY: jh_live_xk29fmz...

{
  "session_id": 198,
  "q": "What are the payment terms across all Q4 vendor invoices?"
}

Example response

{
  "answer": "Net-30 is specified in 11 of 14 vendor invoices reviewed. Three vendors — Meridian Supply Co. (INV-4892), Apex Materials (INV-4834), and Bright Tech (INV-4821) — specify Net-45 terms.",
  "sources": [
    {
      "document_id": 47,
      "document": "meridian-inv.pdf",
      "page": 1
    },
    {
      "document_id": 51,
      "document": "apex-inv.pdf",
      "page": 1
    }
  ],
  "confidence": 0.94,
  "session_id": 198
}

Response fields

Field Type Description
answer string Natural-language answer synthesised from the document corpus.
sources array The specific documents and pages that informed the answer.
confidence float (0–1) Model confidence in the answer. Values below 0.7 indicate low certainty.

Agents — Create Agent

Creates and activates an autonomous agent. Provide a plain-English prompt describing the agent's goal, and declare the tools it is permitted to call. The agent begins listening for its trigger event immediately on creation.

POST /harness/agent/

Headers

Accept: application/json
Content-Type: application/json
X-API-KEY: <api-key>

Request body

Field Type Required Description
prompt string required Plain-English description of the agent's goal and trigger condition. Be specific about the trigger and the desired outcome.
tools string[] required Array of tool identifiers the agent may call. See Available Tools. Principle of least privilege — only include tools required for the task.

Example request

POST https://harness.jheel.io/harness/agent/
Content-Type: application/json
X-API-KEY: jh_live_xk29fmz...

{
  "prompt": "When a new Shopify order is placed, check available stock for each line item in NetSuite. If all items are in stock, confirm the order and send a receipt email via Postmark. If any item is out of stock, flag the order for review.",
  "tools": [
    "shopify.orders.read",
    "shopify.orders.update",
    "netsuite.items.read",
    "postmark.email.send"
  ]
}

Example response

{
  "agent_id": "agt_7xk2mfp",
  "status": "active",
  "trigger": "shopify.order.created",
  "tools_authorized": [
    "shopify.orders.read",
    "shopify.orders.update",
    "netsuite.items.read",
    "postmark.email.send"
  ],
  "created": "2026-06-14T09:12:00.000000Z",
  "updated": "2026-06-14T09:12:00.000000Z"
}

Agents — Get Agent

Retrieves the current status of an agent, including its configuration and execution history. Use this to monitor what the agent has done and inspect its most recent actions.

GET /harness/agent/{agentID}/

Example request

GET https://harness.jheel.io/harness/agent/agt_7xk2mfp/
Accept: application/json
X-API-KEY: jh_live_xk29fmz...

Example response

{
  "agent_id": "agt_7xk2mfp",
  "status": "active",
  "trigger": "shopify.order.created",
  "tools_authorized": [
    "shopify.orders.read",
    "shopify.orders.update",
    "netsuite.items.read",
    "postmark.email.send"
  ],
  "executions": [
    {
      "execution_id": "exe_4ab3c1",
      "triggered_at": "2026-06-14T11:30:00Z",
      "status": "completed",
      "actions": [
        { "tool": "shopify.orders.read",  "result": "success" },
        { "tool": "netsuite.items.read",  "result": "success" },
        { "tool": "shopify.orders.update","result": "success" },
        { "tool": "postmark.email.send",  "result": "success" }
      ]
    }
  ],
  "created": "2026-06-14T09:12:00.000000Z"
}

Agents — Edit Agent

Updates an existing agent's prompt and/or tool list. The agent must be deactivated before editing, then reactivated. A full prompt and tools array is expected — partial updates are not supported.

PUT /harness/agent/{agentID}/edit/

Example request

PUT https://harness.jheel.io/harness/agent/agt_7xk2mfp/edit/
Content-Type: application/json
X-API-KEY: jh_live_xk29fmz...

{
  "prompt": "When a new Shopify order is placed, check stock in NetSuite. If in stock, post a journal entry to NetSuite, confirm the Shopify order, and send a receipt via Postmark.",
  "tools": [
    "shopify.orders.read",
    "shopify.orders.update",
    "netsuite.items.read",
    "netsuite.journal_entries.create",
    "postmark.email.send"
  ]
}

Example response

{
  "agent_id": "agt_7xk2mfp",
  "status": "active",
  "tools_authorized": [
    "shopify.orders.read",
    "shopify.orders.update",
    "netsuite.items.read",
    "netsuite.journal_entries.create",
    "postmark.email.send"
  ],
  "updated": "2026-06-14T14:00:00.000000Z"
}

Agents — Deactivate Agent

Deactivates a running agent. The agent stops listening for trigger events and will not execute. Any in-progress executions at the time of deactivation are allowed to complete.

POST /harness/agent/deactivate/

Request body

Field Type Required Description
agent_id string required The ID of the agent to deactivate.

Example request

POST https://harness.jheel.io/harness/agent/deactivate/
Content-Type: application/json
X-API-KEY: jh_live_xk29fmz...

{
  "agent_id": "agt_7xk2mfp"
}

Example response

{
  "agent_id": "agt_7xk2mfp",
  "status": "deactivated",
  "updated": "2026-06-14T14:30:00.000000Z"
}

Available Tools

The following tools can be declared in an agent's tools array. Only include tools the agent requires — undeclared tools cannot be called at runtime, even if the prompt references them.

NetSuite

netsuite.invoices.read Read invoice records from NetSuite
netsuite.invoices.create Create new invoices in NetSuite
netsuite.journal_entries.read Read journal entries from NetSuite
netsuite.journal_entries.create Post new journal entries to NetSuite
netsuite.sales_orders.read Read sales orders from NetSuite
netsuite.sales_orders.create Create new sales orders in NetSuite
netsuite.items.read Read inventory item data from NetSuite

Shopify

shopify.orders.read Read order data from Shopify
shopify.orders.create Create new orders in Shopify
shopify.orders.update Update existing Shopify orders
shopify.customers.read Read customer records from Shopify
shopify.customers.update Update customer records in Shopify

Postmark

postmark.email.send Send transactional emails via Postmark
postmark.inbox.read Read inbound email messages via Postmark
Additional integrations are in active development. Contact us to request a specific tool or integration.

Recommended Client Flow

Complete document extraction in three requests:

Step 1 — Create session

POST /harness/session/
→ { "ID": 198 }

Step 2 — Upload one or more documents

POST /harness/session/198/document/
→ { "ID": 47, "ExtractedJSON": null }   # processing begins

Multiple documents can belong to the same session:

POST /harness/session/198/document/
→ { "ID": 48, "ExtractedJSON": null }

POST /harness/session/198/document/
→ { "ID": 49, "ExtractedJSON": null }

Step 3 — Poll for results

GET /harness/session/198/document/47/

# Continue until:
#   ExtractedJSON != null  →  success
#   ErrorMessage != ""     →  failure

Response Fields

Common fields returned across document endpoints:

Field Type Description
ID integer Unique identifier for the resource.
SessionID integer The session this document belongs to.
ExtractedJSON object | null Structured extraction result. Null while processing.
ErrorMessage string Empty on success; descriptive failure reason on error.
CostUSD float Processing cost for this document in USD.
ResponseTimeMs integer Total extraction processing time in milliseconds.
AdditionalFields object Model-specific metadata with confidence scores and evidence references.

Notes

  • Document processing is asynchronous. Always poll — never assume immediate results.
  • Multiple documents can belong to a single session. Process related documents together for better RAG query context.
  • CostUSD reflects the per-document processing cost, billed to your account.
  • AdditionalFields contains model-specific extracted metadata with confidence scores — the schema varies by document type.
  • Agents operate on principle of least privilege — only tools explicitly declared in the tools array can be called at runtime.
  • All timestamps are UTC ISO 8601.

Questions or integration issues? Get in touch →