One POST creates a verification. A webhook returns it — parsed JSON, the raw IRS HTML, and a PDF, in whatever shape your LOS actually wants. Built for platforms that own their own origination stack.
# Create a transcript request curl -X POST https://portal.moderntax.io/api/intake/transcript \ -H "x-api-key: mt_live_txn_yourco_xxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "request_token": "SBA-7a-4482", // your id — also the idempotency key "entities": [{ "entity_name": "Atlas Roofing LLC", "tid": "88-1213417", "tid_kind": "EIN", "form_type": "1120S", "years": ["2022", "2023", "2024"] }] }' # 201 Created { "request_id": "uuid", "request_token": "SBA-7a-4482", "status": "irs_queue", "entities": [{ "entity_id": "uuid", "status": "irs_queue" }], "usage": { "used": 47, "remaining": 953 } }
# POST to your endpoint when the pull completes # X-ModernTax-Signature: HMAC-SHA256 hex of the raw body { "request_token": "SBA-7a-4482", "status": "complete", // partial | complete | error "record_id": "uuid", // deterministic — dedupe on this "record_type": "financial_verification", "generated_at": "2026-08-11T10:32:11Z", "entity": { "entity_name": "Atlas Roofing LLC", "tid": "88-1213417", "form_type": "1120S" }, "data": { /* shape per record_type — see moderntax.io/docs */ } }
The whole integration — creating an order, results by poll or webhook, the structured and cross-reference endpoints, and every error code you can hit.
Prefer to read it? The full API reference covers every field. Ordering rather than integrating? See the portal walkthrough.
A signed webhook fires when the pull completes, and GET /api/intake/transcript?token= is there if you'd rather poll.
POST /api/intake/transcript with your entities, TINs, and years. Your request_token is the idempotency key — a retry returns 409, never a double order.
Collect the 8821 signature in your own flow (Persona, DocuSign, wet-sign) and send it back — inline as signed_8821 on the create call or via POST /api/intake/8821-pdf, with signature evidence attached. Or let ModernTax collect it.
Status moves through irs_queue and processing. A credentialed expert on our network works the IRS PPS line with their own CAF — never a single shared credential.
A webhook signed with X-ModernTax-Signature delivers parsed JSON, raw IRS HTML, and PDF. Same-day target available on integrated plans, 24h standard.
Three named shapes — minimal, underwriting, raw. Pass schema= on the results call (GET /api/intake/transcript?token=…&schema=underwriting), or pin an org-wide default in the developer portal at portal.moderntax.io/developer. No parameter and no pin? The legacy response shape, unchanged — nothing breaks when we ship.
Per-entity payload for each schema= value. Every shape shares one envelope; PDF/HTML URLs are 1-hour signed.
// GET /api/intake/transcript?token=SBA-7a-4482&schema=minimal // — just tell me if it's clean { "id": "uuid", "name": "Atlas Roofing LLC", "form": "1120S", "years": ["2022", "2023", "2024"], "status": "completed", "years_filed": ["2022", "2023", "2024"], "years_unfiled": [], "flags": [], // [{type, severity, message}] "pdf": ["https://…"], // 1-hour signed URLs "html": ["https://…"] }
// schema: "underwriting" — everything in minimal, plus the lines a credit memo needs { …all minimal fields…, "financials": [ { "year": "2024", "form": "1120S", "gross_receipts": 4182910, "total_income": 4204118, "total_deductions": 3591630, "total_tax": 0, "account_balance": 0, "accrued_interest": 0, "accrued_penalty": 0, "account_balance_plus_accruals": 0 } ], "tax_liabilities": { "total_assessed": 0, "total_paid": 0, "total_balance": 0, "total_accrued": 0 }, "repayment_plan": { "has_installment_agreement": false, "has_offer_in_compromise": false, "has_currently_not_collectible": false, "details": null, "recommendation": "No balance due and no collection activity — clear to proceed." }, "overall_severity": "CLEAN", // CRITICAL | WARNING | CLEAN "headline": "Filed all 3 requested years. No balance due." }
// schema: "raw" — you parse it yourself { "id": "uuid", "name": "Atlas Roofing LLC", "form": "1120S", "years": ["2022", "2023", "2024"], "status": "completed", "retrieved_at": "2026-08-10T15:42:11Z", "artifacts": [ { "kind": "pdf", "file": "2024-record-of-account.pdf", "url": "https://…", "sha256": "9f2c…a41b" }, { "kind": "html", "file": "2024-record-of-account.html", "url": "https://…", "sha256": "3d81…7c02" }, { "kind": "signed_8821", "file": "signed-8821.pdf", "url": "https://…", "sha256": "77aa…09c3" } ] // sha256 computed at serve time; null for legacy externally-stored artifacts }
An underwriter who logs in sees the request your LOS created — same record, same artifacts, same audit trail. Your engineers integrate; your credit team never has to.
Structured records delivered by webhook — HMAC-signed, with automatic retry and backoff. Configure the URL and secret self-serve in the developer portal.
# your handler POST /webhooks/moderntax X-ModernTax-Signature: 8a3f… # HMAC-SHA256 hex of raw body { "request_token": "SBA-7a-4482", "status": "complete", "record_id": "uuid", "record_type": "financial_verification" }
The identical request in the portal — including the ones nobody ordered by hand. Downloadable indefinitely, for the audit that shows up eight months later.
Every pull runs under a credentialed practitioner's own CAF number and their own fax line. No single credential to get flagged — the failure mode that took the last API-first vendor offline doesn't exist here.
Records of Account and Return Transcripts delivered in the form the SOP expects, with source and retrieval timestamp on every artifact. Audit-defensible, not screenshots.
Enroll a conditioned entity via POST /api/intake/monitoring and we re-poll until it lands, then auto-cancel. Billed only when a fresh pull returns something new — never for an empty check.
A lightweight lien-and-compliance check on a 1099 individual or single-member entity — for vetting brokers, not underwriting a loan. Priced below a full verification.
Work email + company at portal.moderntax.io/sandbox gets you an instant {company}-sandbox key against synthetic data. Production-identical endpoints, 250 requests free — test before you talk to anyone.
Your request_token is the idempotency key — a retried create returns 409, never a double charge or a double pull. Usage against your quota is visible in the developer portal.
All requests authenticate with an x-api-key header against https://portal.moderntax.io. Keys, webhooks, default schema, and usage are managed self-serve at portal.moderntax.io/developer.
| Method | Endpoint | What it does |
|---|---|---|
| POST | /api/webhook/employment-intakeLive in production | Submit an employment & income verification. Takes request_token, employee_name, employee_ssn, and years[]. Returns request_id plus a usage object with requests used and remaining. |
The transcript ordering, authorization-upload, and usage endpoints are documented in the full API reference at moderntax.io/docs. They are not reproduced here so this page can’t drift out of sync with the canonical reference — check the docs, or email matt@moderntax.io and we’ll send the current spec with your sandbox keys.
One flat per-entity price covers the Return Transcript, the Record of Account, entity-transcript detection, and compliance screening — there's no line-item ladder per document type. Where you land depends on committed monthly volume, and we'll quote it on a short call.
| What you get at every price point | Unit rate |
|---|---|
| Per verified entity (TIN) Return Transcript + Record of Account, all requested years · entity-transcript / election-status detection included · compliance flag screening · unlimited team seats · REST API, webhooks and portal access on integrated plans. Rejections are never billed. Nothing re-pulls without you asking. Volume commitments move the rate down from here. | from $39.99/ entity |
A definitive IRS result bills — including "no record of return filed," which is a real underwriting finding. Rejections (bad EIN, name mismatch, signer not on record) and abandoned pulls never bill, and we return the specific field to fix.
Tell us your expected monthly entity volume and whether you're pulling for your own book or reselling under your own brand. We come back with a firm per-entity rate the same day — no procurement cycle to get a number. Quotes already in flight are honored exactly as written.
Tell us your schema preference and volume band and we'll provision sandbox keys plus a staging webhook the same day — no procurement cycle to start testing.