Employment & Income Verification API
Submit employment verification requests, poll for completion status, and receive structured W-2 and 1099 income data — all sourced from IRS Wage & Income transcripts.
Getting an API Key
Contact matt@moderntax.io to request API access. You'll receive an API key and your first 3 requests are free.
Authentication
All API requests require an x-api-key header with your API key.
x-api-key: mt_live_emp_YOUR_API_KEY
Keep your API key secret. Do not expose it in client-side code or public repositories.
Base URL
https://portal.moderntax.io
Submit Verification Request
Create a new employment/income verification request for a given employee.
POST /api/webhook/employment-intake
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| request_token | string | Yes | Your unique identifier for this request. Used for deduplication and result retrieval. |
| employee_name | string | Yes | Full legal name of the employee. |
| employee_ssn | string | Yes | Social Security Number. Masked to last 4 digits in storage (XXX-XX-1234). |
| years | string[] | Yes | Tax years to verify (e.g., ["2025", "2024", "2023"]). |
| employee_address | object | No | Object with street, city, state, zip fields. |
Example Request
curl -X POST https://portal.moderntax.io/api/webhook/employment-intake \
-H "Content-Type: application/json" \
-H "x-api-key: mt_live_emp_YOUR_API_KEY" \
-d '{
"request_token": "emp_req_20260316_001",
"employee_name": "Jane Doe",
"employee_ssn": "123-45-6789",
"years": ["2025", "2024", "2023"],
"employee_address": {
"street": "123 Main St",
"city": "Austin",
"state": "TX",
"zip": "78701"
}
}'
Example Response
{
"success": true,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"entity_id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
"request_token": "emp_req_20260316_001",
"usage": {
"used": 1,
"remaining": 2,
"limit": 3
}
}
Get Verification Result
Poll for the status and results of a verification request. Returns structured data when the request is completed.
GET /api/webhook/employment-result?token={request_token}
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| token | string | Yes | The request_token you provided when submitting the request. |
Example Request
curl https://portal.moderntax.io/api/webhook/employment-result?token=emp_req_20260316_001 \
-H "x-api-key: mt_live_emp_YOUR_API_KEY"
Response — Pending
{
"request_id": "emp_req_20260316_001",
"status": "pending_irs_call",
"request_status": "submitted",
"entity_status": "pending",
"message": "Request is still being processed. Check back later."
}
Response — Completed
{
"request_id": "emp_req_20260316_001",
"status": "completed",
"result": {
"taxpayer_name": "Jane Doe",
"ssn_last_4": "6789",
"employers": [
{
"name": "Acme Corp",
"ein": "12-3456789",
"is_peo": false,
"years": {
"2025": { "w2_wages": 95000.00, "federal_tax": 14250.00 },
"2024": { "w2_wages": 88000.00, "federal_tax": 13200.00 }
}
}
]
},
"transcript_urls": [
"https://portal.moderntax.io/storage/v1/..."
],
"completed_at": "2026-03-18T14:30:00.000Z"
}
Polling Recommendation
Poll every 30–60 minutes. Most requests complete same day or next business day. transcript_urls contain time-limited signed URLs (valid for 1 hour).
Push Result Data
Push structured employment data back to ModernTax after processing transcripts on your end. This marks the request as completed.
PATCH /api/webhook/employment-result?token={request_token}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| employment_data | object | Yes | Structured employment verification data. See data schemas below. |
Example Request
curl -X PATCH "https://portal.moderntax.io/api/webhook/employment-result?token=emp_req_20260316_001" \
-H "Content-Type: application/json" \
-H "x-api-key: mt_live_emp_YOUR_API_KEY" \
-d '{
"employment_data": {
"taxpayer_name": "Jane Doe",
"ssn_last_4": "6789",
"employers": [
{
"name": "Acme Corp",
"ein": "12-3456789",
"is_peo": false,
"years": {
"2025": { "w2_wages": 95000.00, "federal_tax": 14250.00 },
"2024": { "w2_wages": 88000.00, "federal_tax": 13200.00 }
}
}
]
}
}'
Example Response
{
"success": true,
"request_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"entity_id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210",
"status": "completed"
}
Error Codes
All errors return a JSON object with an error field describing the issue.
| Status | Error | Description |
|---|---|---|
| 401 | Missing x-api-key header | No API key was provided in the request headers. |
| 401 | Invalid API key | The provided API key does not match any active client. |
| 400 | request_token is required | Missing required field in request body. |
| 404 | Request not found | No request found with the given token for your API key. |
| 409 | Duplicate request_token | A request with this token already exists. Response includes existing_request_id. |
| 429 | API request limit exceeded | You've reached your API quota. Response includes usage object with used and limit. |
Rate Limits & Quotas
Each API key has a request quota. The current usage is returned in every successful POST response.
Free Tier
First 3 requests free. No credit card required.
Higher Limits
Contact matt@moderntax.io for volume pricing and increased quotas.
Data Schemas
EmploymentData
The structured employment verification result object.
interface EmploymentData {
taxpayer_name: string;
ssn_last_4: string;
employers: EmploymentEmployer[];
}
interface EmploymentEmployer {
name: string;
ein: string;
is_peo: boolean; // Professional Employer Organization flag
years: Record<string, EmploymentYearData>;
}
interface EmploymentYearData {
w2_wages?: number; // W-2 Box 1: Wages, tips, other compensation
federal_tax?: number; // W-2 Box 2: Federal income tax withheld
social_security?: number; // W-2 Box 3: Social security wages
medicare_wages?: number; // W-2 Box 5: Medicare wages
form_1099_income?: number; // 1099-NEC/MISC non-employee compensation
}