L E N D I Q
The official Python SDK for the LendIQ API.
Turn months of manual underwriting into a single API call.
Get API Key · Documentation · API Reference
from lendiq import LendIQClient
client = LendIQClient(api_key="liq_live_...")
deal = client.deals.create(business_name="Acme Trucking LLC")
client.documents.upload(deal.id, "statements/chase_jan.pdf")
result = client.deals.get(deal.id)
print(result.recommendation.decision) # "approved"That PDF just went through Gemini-powered extraction, transaction screening, tamper detection, 12-factor health scoring, and a full underwriting recommendation. Your team didn't write a single rule.
|
|
| LendIQ | Ocrolus | LendAPI | Plaid (Asset Reports) | DIY (in-house) | |
|---|---|---|---|---|---|
| Upload PDF → full underwriting decision | Yes | No | Partial | No | Build it yourself |
| Bank statement + tax return + P&L support | All three | Statements only | Statements only | No PDFs | Depends on scope |
| Gemini native PDF extraction | Yes | Template OCR | Template OCR | N/A | Build it yourself |
| Tamper / fraud detection | Built in | Add-on | No | No | Build it yourself |
| Health scoring (12 sub-factors) | Built in | No | Basic | No | Build it yourself |
| Underwriting recommendation engine | Built in | No | Basic | No | Build it yourself |
| Custom rulesets with version history | Yes | No | No | No | Build it yourself |
| MCA position detection | Yes | No | No | No | Build it yourself |
| Real-time SSE streaming | Yes | Polling | Polling | Polling | Build it yourself |
| Typed SDKs (Python + TypeScript) | Both | Python only | None | Multiple | N/A |
| Pricing | Per document | Per document | Per document | Per connection | Engineering time |
We don't just extract data from bank statements. We understand them — and give you a decision you can act on.
pip install lendiqRequires Python 3.10+. Only two dependencies:
httpxandpydantic.
Both clients have identical APIs. Pick the one that fits your stack.
# Sync
with LendIQClient(api_key="liq_live_...") as client:
deals = client.deals.list(status="ready")# Async
from lendiq import AsyncLendIQClient
async with AsyncLendIQClient(api_key="liq_live_...") as client:
deals = await client.deals.list(status="ready")Every method returns a Pydantic model. Not dict. Not Any. Real models with real autocompletion.
detail = client.deals.get(deal_id)
# IDE knows every field, every nested object, every type
detail.health.health_score # float
detail.health.health_grade # str
detail.recommendation.decision # "approved" | "conditional" | "declined"
detail.recommendation.risk_factors # list[str]
detail.recommendation.strengths # list[str]
detail.financials.avg_monthly_deposits # float
detail.mca.mca_credit_score # float | None
# 12 health sub-factors, individually scored and weighted
for name, factor in detail.health.factors.items():
print(f"{name}: {factor.score}/{factor.max} (weight: {factor.weight})")All response models are forward-compatible (extra="allow"). New API fields are accepted automatically — your code never breaks on deploy.
Upload a PDF and get back structured intelligence — no OCR pipeline, no prompt engineering, no infra to manage.
doc = client.documents.get(doc_id)
# Extraction metadata
doc.extraction_method # "gemini_native_pdf"
doc.extraction_confidence # 0.94
doc.document_type # "bank_statement"
# Tamper detection
doc.integrity.tampering_risk_level # "clean" | "low" | "medium" | "high"
# Financial analysis (bank statements)
doc.analysis.average_daily_balance # 16215.30
doc.analysis.total_deposits # 48920.00
doc.analysis.health_score # 78.5
doc.analysis.health_grade # "B"
# Identity verification (driver's licenses)
doc.driver_license_analysis.full_name # "John Smith"
doc.driver_license_analysis.expiration_date # "2028-06-15"
# Bank verification (voided checks)
doc.voided_check_analysis.routing_number # "021000021"
doc.voided_check_analysis.is_voided # TrueLet prospects try LendIQ before they sign up. The instant endpoint processes a PDF in under 2 seconds with no data persistence.
result = client.instant.analyze("statement.pdf")
print(result.summary.total_deposits) # 284500.00
print(result.summary.total_mca_positions) # 3
print(result.summary.avg_revenue_quality) # 0.82
# Per-file breakdown
for file in result.results:
print(file.bank_name, file.nsf_count, file.mca_daily_obligation)Watch documents process in real time. No polling.
for event in client.events.stream(deal_id=deal_id):
if event.event == "stage":
print(f"Stage: {event.data}") # "classifying" → "extracting" → "screening" → "scoring"
elif event.event == "complete":
print("Analysis complete")Forget page math. Iterate over thousands of records with a single loop.
for deal in client.deals.list_all(status="ready"):
print(deal.business_name, deal.health_grade)
# Typed as DealSummary — full autocompletionEvery error is a typed exception with the context you need to debug. No parsing strings.
from lendiq.exceptions import NotFoundError, RateLimitError, ValidationError
try:
client.deals.get(deal_id)
except NotFoundError:
# e.status_code == 404
pass
except RateLimitError as e:
# e.retry_after — seconds until you can retry
pass
except ValidationError as e:
# e.body — full validation error details
pass
# Every error has e.request_id for instant support correlationfrom lendiq.webhooks import verify_signature
# HMAC-SHA256 with constant-time comparison. Timing attacks don't apply.
verify_signature(payload=body, signature=headers["X-Webhook-Signature"], secret="whsec_...")| Automatic retries | Exponential backoff with jitter. Honors Retry-After. Safe for mutations — POST/PUT/PATCH only retry on connection errors, never on HTTP status codes. |
| Idempotency | Pass an idempotency key on any write. Retry all you want. |
| Request tracking | Every request gets a UUID. Every error includes it. client.last_request_id is always available. |
| Timeouts | Sensible defaults per operation type. TIMEOUT_READ (10s), TIMEOUT_WRITE (30s), TIMEOUT_UPLOAD (120s), TIMEOUT_REPORT (300s). |
| Forward compatible | All models use extra="allow". API updates never break your code. |
| PEP 561 | py.typed marker included. Full mypy --strict support. |
client = LendIQClient(
api_key="liq_live_...", # required
base_url="https://iq.lend.works", # default
timeout=30.0, # default (seconds)
max_retries=2, # default
logger=logging.getLogger("lendiq"), # optional debug logging
)Every endpoint in the LendIQ API has a typed method in this SDK.
| Resource | What it does | |
|---|---|---|
| Core | client.deals |
CRUD, decision, evaluate, notes, stats, analytics, batch |
client.documents |
Upload, bulk upload, status, reprocess, triage, classify | |
client.transactions |
List, correct, corrections history | |
client.exports |
Deal and document CSV/PDF exports | |
client.rulesets |
Underwriting criteria CRUD, versioned, set default | |
| Intelligence | client.instant |
Free-tier instant PDF analysis (sub-2s, no persistence) |
client.lvl |
Business validation runs, call queue, SAM entities | |
client.sam_profiles |
SAM.gov search profiles, watchers, automated triggers | |
client.reviews |
Document review queue, approve/correct workflow | |
| Real-time | client.events |
SSE streams for deals, org events, batch progress |
client.webhooks |
Webhook config, test, delivery logs, retry | |
client.notifications |
In-app notifications and preferences | |
client.push |
Web push subscriptions | |
| Platform | client.team |
Invite, update, deactivate members |
client.keys |
API key management | |
client.shares |
Public deal share links | |
client.ingest |
Bulk CRM ingest with batch tracking | |
client.crm |
Provider config, field mapping, bidirectional sync | |
client.integrations |
Slack, Teams, SMTP notification channels | |
client.admin |
Health, usage, error logs, DLQ, pipeline settings | |
client.usage |
Metering and processing time analytics | |
client.oauth |
Client credentials token exchange |
Plus 5 sub-resources on every deal:
client.deals.comments.list(deal_id) # threaded discussion
client.deals.assignments.create(deal_id) # assign reviewers
client.deals.doc_requests.create(deal_id) # request missing docs
client.deals.timeline.list(deal_id) # full activity history
client.deals.users.search(q="jane") # find team members| Method | Rate limit (429) | Server error (5xx) | Connection error |
|---|---|---|---|
| GET / DELETE | Retry | Retry | Retry |
| POST / PUT / PATCH | — | — | Retry |
Exponential backoff with jitter. 0.5 s base, 30 s cap. Honors Retry-After.
This SDK is actively maintained by the LendIQ engineering team. We release weekly, respond to issues within 24 hours, and treat SDK quality with the same rigor as our core platform.
If something isn't right, open an issue. We'll fix it.
MIT — use it however you want.