Skip to main content

Overview

Two patterns: webhook (Pathway calls you when done) or polling (you check status yourself). Both start with the same submit call.

1. Submit documents

POST /submit-book accepts multipart form data. Pass one or more PDFs. Pathway auto-classifies each file as bank statement, credit report, tax form, or loan application.
import requests

API_BASE = "https://api.lendpathway.com/api"
TOKEN = "pat_your_token_here"
headers = {"Authorization": f"Bearer {TOKEN}"}

files = [
    ("files", ("jan_statement.pdf", open("jan.pdf", "rb"), "application/pdf")),
    ("files", ("feb_statement.pdf", open("feb.pdf", "rb"), "application/pdf")),
    ("files", ("credit_report.pdf", open("credit.pdf", "rb"), "application/pdf")),
]

r = requests.post(
    f"{API_BASE}/submit-book",
    headers=headers,
    files=files,
    data={"book_name": "Smith Auto Body Q3 2025"}
)

book_id = r.json()["book_id"]
print(f"Book created: {book_id}")
# Parsing starts immediately in the background
Multiple files in one call is fine. Pathway processes them together as a single deal and cross-references across document types when computing analytics.

2a. Wait with a webhook

Add webhook_url to your submission. Pathway sends a POST to that URL when parsing finishes.
r = requests.post(
    f"{API_BASE}/submit-book",
    headers=headers,
    files=files,
    data={
        "book_name": "Smith Auto Body Q3 2025",
        "webhook_url": "https://your-server.com/pathway-webhook"
    }
)
Webhook payload sent to your URL on completion:
{
  "book_id": "99cc93e6-1f3f-42b1-9fe4-ba5a95be9c78",
  "status": "completed",
  "book_url": "https://app.lendpathway.com/books/99cc93e6-1f3f-42b1-9fe4-ba5a95be9c78"
}
status is one of completed, failed, cancelled. Example receiver (FastAPI):
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class WebhookPayload(BaseModel):
    book_id: str
    status: str
    book_url: str

@app.post("/pathway-webhook")
async def handle_webhook(payload: WebhookPayload):
    if payload.status == "completed":
        analytics = await fetch_book_analytics(payload.book_id)
    elif payload.status == "failed":
        print(f"Parse failed for book {payload.book_id}")

    return {"ok": True}

2b. Wait with polling

Poll GET /books/:id every few seconds until parse_status is terminal.
import time

def wait_for_parse(book_id, poll_interval=5, timeout=600):
    start = time.time()
    while True:
        r = requests.get(f"{API_BASE}/books/{book_id}", headers=headers)
        book = r.json()
        status = book["parse_status"]
        message = book.get("parse_status_message", "")

        print(f"  [{status}] {message}")

        if status == "completed":
            return book
        if status in ("failed", "cancelled"):
            raise Exception(f"Parse ended with status: {status}")
        if time.time() - start > timeout:
            raise TimeoutError("Parse timed out")

        time.sleep(poll_interval)

book = wait_for_parse(book_id)
print(f"Done: {book['parse_status_message']}")
# Done: Processed 3 bank_statements
parse_status_message tells you what Pathway parsed, e.g. Processed 3 bank_statements or Processed 1 credit_report, 2 bank_statements. Good for confirming file classification.

3. Fetch results

Once parse_status is completed, call /analytics for bank statement data.
r = requests.get(f"{API_BASE}/books/{book_id}/analytics", headers=headers)
analytics = r.json()

print(f"Deposits:          ${analytics['total_deposits']:,.2f}")
print(f"True revenue:      ${analytics['true_revenue']:,.2f}")
print(f"Avg daily balance: ${analytics['average_daily_balance']:,.2f}")
print(f"Days negative:     {analytics['days_negative_balance']}")
print(f"DTI:               {analytics.get('debt_to_income_ratio', 'N/A')}%")
print(f"Positions found:   {len(analytics['positions'])}")
For credit report data, read from book_meta:
r = requests.get(f"{API_BASE}/books/{book_id}", headers=headers)
book = r.json()
cr = book["book_meta"]["parser_v2_credit_report"]

entity = cr["primary_entity"]
print(f"Subject: {entity['full_name']}")

for bureau_data in cr["credit_report_body"]:
    bureau = bureau_data["credit_bureau"]["display_name"]
    fico = bureau_data.get("fico_score", {})
    print(f"{bureau}: FICO {fico.get('score')}")
    print(f"  Accounts: {len(bureau_data['underwritten_accounts'])}")
For tax forms, use /tax-analytics:
r = requests.get(f"{API_BASE}/books/{book_id}/tax-analytics", headers=headers)
tax = r.json()

for year in tax["years"]:
    print(f"{year['tax_year']}: qualifying income = ${year['total_qualifying_income']:,.2f}")

4. Full flow in one script

import requests, time

API_BASE = "https://api.lendpathway.com/api"
TOKEN = "pat_your_token_here"
headers = {"Authorization": f"Bearer {TOKEN}"}

# 1. Submit
with open("statement.pdf", "rb") as f:
    r = requests.post(
        f"{API_BASE}/submit-book",
        headers=headers,
        files={"files": ("statement.pdf", f, "application/pdf")},
        data={"book_name": "Test book"}
    )
book_id = r.json()["book_id"]
print(f"Submitted: {book_id}")

# 2. Poll
while True:
    status = requests.get(f"{API_BASE}/books/{book_id}", headers=headers).json()["parse_status"]
    if status == "completed":
        break
    if status in ("failed", "cancelled"):
        raise Exception(f"Parse failed: {status}")
    time.sleep(5)

# 3. Get analytics
analytics = requests.get(f"{API_BASE}/books/{book_id}/analytics", headers=headers).json()
print(f"True revenue: ${analytics['true_revenue']:,.2f}")
print(f"Positions: {len(analytics['positions'])}")