ModernTax Partner API
Programmatic IRS transcript verification: submit an entity, obtain Form 8821 authorization, and receive the pulled transcripts plus a structured compliance read — by polling or by webhook.
Overview
A typical automated integration (how a reseller like a lending platform runs it end to end):
- Submit one or more entities to
POST /api/intake/transcript. - Authorize each entity with a signed IRS Form 8821 — either upload a pre-signed PDF you collected yourself (
/api/intake/8821-pdf), or let ModernTax collect the signature (/api/intake/8821). See Authorization. - Receive results — poll
GET /api/intake/transcript?token=, or have ModernTax POST them to your webhook.
Every endpoint below is authenticated with an x-api-key header. The portal also exposes cookie-authenticated admin/expert/processor endpoints; those are internal and not part of this contract.
Authentication
All requests require an x-api-key header issued by ModernTax. Contact matt@moderntax.io to provision a key; new accounts include free test requests.
x-api-key: <your_api_key>
Content-Type: application/json # or multipart/form-data where noted
Keys are stored as SHA-256 hashes and constant-time verified on every request. A missing or invalid key returns 401 via the same code path, so errors never reveal whether a partial match exists.
Base URL
https://portal.moderntax.io
Submit a transcript request
Creates a request with one or more entities and queues them for IRS retrieval.
/api/intake/8821 if you want ModernTax to collect the signature.Request
{
"request_token": "your-loan-12345", // unique per account; idempotency key
"loan_number": "your-loan-12345", // optional; used in invoice itemization
"entities": [
{
"entity_name": "ACME Holdings LLC",
"tid": "12-3456789",
"tid_kind": "EIN", // "EIN" or "SSN"
"form_type": "1120S", // optional; inferred from tid_kind if omitted
"years": ["2022","2023","2024"],
"address": "123 Main St", "city": "Austin", "state": "TX", "zip_code": "78701",
"loan_officer_name": "Jane Rep", // optional
"loan_officer_email": "jane@lender.com",
"fiscal_year_end_month": 12 // optional
}
]
}
| Field | Req | Notes |
|---|---|---|
request_token | yes | Your unique id for the request. Reusing one returns 409. |
loan_number | no | Falls back to request_token. Used on invoices. |
entities[].entity_name | yes | Legal name on file with the IRS. |
entities[].tid / tid_kind | yes | EIN (XX-XXXXXXX) or SSN (XXX-XX-XXXX); "EIN"/"SSN". |
entities[].years | yes | 4-digit years, 1990–2028. |
entities[].form_type | no | 1120, 1120S, 1065, 1040, … Inferred from tid_kind if omitted. |
Response 201
{
"success": true,
"request_id": "uuid",
"request_token": "your-loan-12345",
"loan_number": "your-loan-12345",
"status": "irs_queue",
"entities": [
{ "entity_id": "uuid", "entity_name": "ACME Holdings LLC",
"form_type": "1120S", "years": ["2022","2023","2024"], "status": "irs_queue" }
],
"usage": { "used": 47, "remaining": 953, "limit": 1000 }
}
Errors: 401 (auth), 402 (account not enrolled in billing — see Pricing), 409 (duplicate request_token).
Authorization — IRS Form 8821
The IRS requires a signed Form 8821 authorizing ModernTax as designee before transcripts can be pulled. Two integration models:
A. Upload a pre-signed 8821 (you collect the signature)
For partners who obtain the borrower's signature through their own workflow (DocuSign, wet-sign, etc.). The entity advances straight to 8821_signed. This is the model a fully-automated reseller uses.
# multipart/form-data
file: <signed PDF, application/pdf, max 10 MB> (required)
request_token: your-loan-12345 (required)
entity_id: uuid # or entity_name if the request has one entity
years: "2022,2023,2024" # optional override
form_type: "1120S" # optional override
{ "success": true,
"entity": { "id":"uuid","name":"ACME Holdings LLC","status":"8821_signed",
"signed_8821_url":"https://…1h-expiry…","years":["2022","2023","2024"],"form_type":"1120S" } }
B. Let ModernTax collect the signature
Submit entities with signer details (CSV/XLSX file or JSON { entities: [...] }) and ModernTax generates a pre-filled 8821, e-mails the signer for signature, then proceeds automatically.
CSV columns: entity_name, tid, tid_kind, email, signer_first_name, signer_last_name, years, address, city, state, zip, form_type.
{ "request_id":"uuid","entities_created":12,"signature_requests_sent":12,"status":"8821_sent" }
Poll for results
Returns every entity's current status, 1-hour signed transcript URLs, and a compliance read.
{
"request_id": "your-loan-12345",
"status": "completed", // collapses to "completed" | "pending"
"request_status": "completed", // raw: submitted | 8821_sent | 8821_signed | irs_queue | processing | completed | failed
"completed_at": "2026-05-09T10:32:11Z",
"entities": [{
"entity_id":"uuid","entity_name":"ACME Holdings LLC","tid":"12-3456789","form_type":"1120S",
"years":["2022","2023","2024"],"status":"completed",
"signed_8821_url":"https://…1h-expiry…","signature_created_at":"2026-05-08T…",
"transcript_urls":["https://…/2022-record-of-account.pdf", "…"],
"transcript_html_urls":["https://…"],
"compliance": {
"severity":"WARNING", // CRITICAL | WARNING | CLEAN (max across forms)
"flags":[{"type":"BALANCE_DUE","severity":"WARNING","message":"Account balance: $4,287.21"}],
"financials":{"grossReceipts":1240000,"totalTax":42000,"accountBalance":4287.21,"accruedInterest":0,"accruedPenalty":0},
"recent_transactions":[{"code":"150","explanation":"Tax return filed","date":"2024-04-12","amount":"42000"}] // ≤10, newest first
}
}]
}
Structured JSON
Machine-readable parse of a completed entity — filings, per-year compliance, and an income baseline — for resellers who consume data rather than files. Same x-api-key auth. A companion GET /api/v1/transcripts/{entityId}/cross-reference compares declared vs. IRS-of-record values.
{ "entity": {…}, "filings": [{ "year":"2023","form":"1120S","filed":true,… }],
"compliance": {…}, "income_baseline": {…} }
Enroll in monitoring
{ "request_token":"your-loan-12345", "entity_name":"ACME Holdings LLC",
"frequency":"annual", // weekly | monthly | quarterly | annual | custom
"custom_interval_days":365, // required if frequency=="custom"
"skip_initial_pull":true, "expires_at":"2031-05-09", "next_pull_date":"2027-04-15" }
Returns the created subscription. If skip_initial_pull=false (default) an immediate_pull is queued. An entity with an active/paused subscription returns 409 with the existing one.
Webhooks — push result delivery
Results are pushed to the webhook URL ModernTax provisions for your account during onboarding (there is no per-request callback_url field). Delivery fires when an entity's transcripts are completed. There is no separate event for intermediate steps like 8821 signed or IRS queued — poll for those.
Headers
Content-Type: application/json
User-Agent: ModernTax-Webhook/1.0
X-ModernTax-Signature: <hex HMAC-SHA256 of the raw body, keyed with your webhook secret>
x-moderntax-event header.Payload
Two formats are supported; your account is configured for one:
// files format
{ "request_token":"your-loan-12345", "status":"complete", // partial | complete | error
"files":[{ "file_id":"uuid","type":"record_of_account","year":"2023",
"entity_name":"ACME Holdings LLC","html":"<…>","created_at":"…" }] }
// structured format
{ "request_token":"your-loan-12345","status":"complete","record_id":"uuid",
"record_type":"account_transcript","generated_at":"…","entity":{…},"data":{…},"raw_html":"…" }
Retries
On any non-2xx response ModernTax retries up to 5 times with backoff: 10s, 30s, 90s, 5m, 15m.
Employment & income verification
A separate product for W-2/1099 verification. Same x-api-key scheme.
Poll returns parsed employment_data instead of transcripts. Ask for the employment schema when provisioning.
Errors
| Status | Meaning |
|---|---|
400 | Validation error (bad TID, non-PDF upload, file > 10 MB, missing required field). |
401 | Missing or invalid x-api-key. |
402 | Account not enrolled in billing — a payment method / billing setup is required before ordering. |
404 | request_token or entity not found for your account. |
409 | Duplicate request_token, or an entity already has a monitoring subscription. |
429 | Account request quota reached (body includes usage). |
Rate limits
A cumulative request quota is enforced per account when configured. Exceeding it returns 429 with { "error": "...", "usage": { "used", "limit" } }. Quotas are set with your plan — contact sales to raise one.
System status
No auth. Returns { "status": "ok" } when healthy — safe to poll for monitoring.
Pricing & quotas
API accounts are billed monthly via ACH (Mercury) or Stripe at your negotiated rates. Representative default tier:
| Item | Rate |
|---|---|
| Transcript pull (per entity — record-of-account + return transcript, up to 3 yrs) | $39.99 |
| Monitoring enrollment (one-time per entity) | $19.99 |
| Monitoring per-pull (billed only when fresh transcripts are delivered) | $59.98 |
| Entity pre-validation (filing-requirement check) | $19.99 |
Setup fee and monthly minimums apply per contract; volume pricing above 100 pulls/month — contact sales@moderntax.io.
Security & compliance
- SOC 2 Type I complete; Type II in progress.
- Encrypted in transit (TLS 1.2+) and at rest (AES-256; encrypted SSN/credential columns).
- API keys SHA-256 hashed, constant-time verified.
- Per-tenant storage isolation via Postgres Row-Level Security on the storage bucket.
- Every partner request and result fetch is audit-logged with client identity, timestamp, and token.
- Signed transcript/8821 URLs expire in 1 hour.
For SOC 2 evidence or vendor questionnaires: security@moderntax.io.
Versioning
This document describes the v1 surface (the /api/intake/* endpoints and /api/v1/transcripts/*). Breaking changes land under a new version path; existing endpoints remain stable.