> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.spreadspace.app/api/api-reference/w2s/get-w-2-s/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.spreadspace.app/_mcp/server. # List all W-2s GET https://api.spreadspace.app/api/borrowers/{borrower_id}/extractions/w2s Lists every usable Form W-2 uploaded on its own on the borrower's file. Duplicates and failed extractions are left out, and you can pass `loan_id` to narrow the list to one loan. Requires the `extractions:read` scope. Rate limit: 200 requests per minute per key (the `api` lane). Reference: https://docs.spreadspace.app/api/api-reference/w2s/get-w-2-s ## Authentication - `Authorization` header (bearer token, required) — Bearer token. Use `ss_live_…` for live data or `ss_test_…` for the sandbox (test mode). See [Authentication](https://docs.spreadspace.app/api/authentication). ## Request ### Path parameters - `borrower_id` (string, required) — The borrower's id. ### Query parameters - `loan_id` (string, optional) — Narrow the list to one loan. ### Headers - `SpreadSpace-Version` (string, optional) — Pin the API version, e.g. `2026-07-19`. Omit to get the latest. See [Versioning](https://docs.spreadspace.app/api/versioning). ## Response ### 200 OK - `borrower_id` (string, required) — The borrower the documents belong to. - `forms` (list of W2ReportDataListItem, required) — One row per document. ## Errors ### 400 Bad Request Error Bad request: validation failed, the cursor is malformed, or the API version is unknown. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 401 Unauthorized Error Unauthorized: the bearer token or API key is missing or invalid. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 402 Payment Required Error Payment required: the standard error envelope with `type` `subscription_required` when the workspace has no active or trialing subscription, or `billing_required` where a plan entitlement applies. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 403 Forbidden Error Forbidden: authentication succeeded but the caller is not permitted to perform this action, for example an API key missing the required scope, an embed session reaching a loan it was not minted for, or a feature outside the workspace's plan. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 404 Not Found Error Not found: the resource does not exist or is not visible to the calling tenant. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 429 Too Many Requests Error Too many requests: the rate limit was hit, or an idempotency-key replay is still in progress. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ### 500 Internal Server Error Internal server error: an unexpected failure. Quote the `request_id` in support tickets. A mutation sent with an `Idempotency-Key` replays this fault under that key rather than re-running; confirm the resource state before resending with a new key. - `error` (ApiErrorBody, required) — Inner body of the canonical API error envelope. ## Types ### W2ReportDataListItem One row of the Form W-2 list: the document's identity and its extracted object. - `extracted_document_id` (string, required) — Identifier of the extracted document. - `document_category` (string, required) — The document category the extraction is stored under. - `report_data` (W2ReportData, required) — The extracted object, in the family's shape. ### ApiErrorBody Inner body of the canonical API error envelope. - `type` (string, required) — Stable error type identifier. Pattern-match on this value, not the human-readable message. - `message` (string, required) — Human-readable error message. Subject to wording changes; do not parse. - `request_id` (string, optional, nullable) — Per-request correlation ID (matches `X-Request-ID` response header). Quote in support tickets. - `details` (map from string to string, optional, nullable) — Structured detail. Some error types populate documented keys in every environment: a version conflict (409) carries `current_version`, the version the resource is actually at, so the client can reload and re-apply. Free-form diagnostic detail beyond those keys appears in development environments only. An `insufficient_credits` 402 carries `balance_usd`, `reserved_usd`, `in_flight_docs`, `incoming_docs` and `per_doc_reservation_usd` as decimal strings. ### W2ReportData A Form W-2, Wage and Tax Statement, uploaded on its own: the boxes of every statement in the file, with the employee's Social Security number reduced to its last four digits. Money is a decimal string with two decimals. - `form` ("w2", required) — Always `w2`. - `data` (W2ReportData_W2Data, required) — The boxes of the first statement in the file, with every statement of the file under `forms_w2`. - `metadata` (W2ReportData_W2Metadata, required) — How the file was read. - `k1_partners` (list of string, required) — Always empty on a Form W-2. - `statements` (list of string, required) — Always empty on a Form W-2. - `depreciation_reports` (W2ReportDataDepreciationReports, optional, nullable) — Always null on a Form W-2. ### W2ReportData_W2Data The statements a Form W-2 upload prints, the first statement's boxes at the top level, every statement under forms_w2, and the employee's identity beside them. - `copy` (string, required, nullable) — The copy letter printed on the form (A, B, C, D, 1 or 2), when the print carries one. - `tax_year` (integer, required, nullable) — The tax year printed beside the form title. - `control_number` (string, required, nullable) — Box d, control number, as printed. - `employer_ein` (string, required, nullable) — Box b, employer identification number, masked to the last four digits. - `employer_name` (string, required, nullable) — Box c, the employer's name. - `employer_address` (string, required, nullable) — Box c, the employer's address below the name, on one line. - `employee_name` (string, required, nullable) — Box e, the employee's first name, initial and last name, as printed. - `employee_ssn_last4` (string, required, nullable) — Box a, the last four digits of the employee's social security number; the rest of the number is never served. - `box_1_wages` (string, required, nullable) — Box 1, wages, tips, other compensation. - `box_2_federal_tax_withheld` (string, required, nullable) — Box 2, federal income tax withheld. - `box_3_ss_wages` (string, required, nullable) — Box 3, social security wages. - `box_4_ss_tax_withheld` (string, required, nullable) — Box 4, social security tax withheld. - `box_5_medicare_wages` (string, required, nullable) — Box 5, Medicare wages and tips. - `box_6_medicare_tax_withheld` (string, required, nullable) — Box 6, Medicare tax withheld. - `box_7_ss_tips` (string, required, nullable) — Box 7, social security tips. - `box_8_allocated_tips` (string, required, nullable) — Box 8, allocated tips. - `box_10_dependent_care_benefits` (string, required, nullable) — Box 10, dependent care benefits. - `box_11_nonqualified_plans` (string, required, nullable) — Box 11, nonqualified plans. - `box_12` (list of W2ReportData_W2Box12Item, required) — Box 12, one entry per printed code and amount, 12a through 12d. - `box_13_statutory_employee` (boolean, required, nullable) — Box 13, the statutory employee box, true when checked. - `box_13_retirement_plan` (boolean, required, nullable) — Box 13, the retirement plan box, true when checked. - `box_13_third_party_sick_pay` (boolean, required, nullable) — Box 13, the third-party sick pay box, true when checked. - `box_14_other` (list of W2ReportData_W2Box14Item, required) — Box 14, other, one entry per printed label and amount. - `box_14b_tipped_occupation_codes` (list of string, required) — Box 14b, Treasury tipped occupation codes, on a form that prints the box. - `state_rows` (list of W2ReportData_W2StateRow, required) — Boxes 15 through 17, one row per state. - `local_rows` (list of W2ReportData_W2LocalRow, required) — Boxes 18 through 20, one row per locality. - `omb_number` (string, required, nullable) — The OMB number printed on the form, 1545-0008 or 1545-0029. - `layout` (enum, required) — The printing of the statement: irs_1up, the IRS form with one statement per page; irs_4up, the four-per-page sheet; substitute, a payroll or preparer print. - Allowed values: `irs_1up`, `irs_4up`, `substitute` - `source_pages` (list of integer, required) — The pages of the uploaded file the statement is printed on, counting from one; several when the upload repeats it. - `rescued_fields` (list of string, required) — The boxes whose figure was read from the page as a whole rather than from the box itself; empty when every figure was read from its box. - `forms_w2` (list of W2ReportData_FormW2, required) — Every distinct statement the upload prints, one per employer, in document order; the first is the one at the top level. - `taxpayer_name` (string, required, nullable) — The employee's name printed in box e of the first statement. - `ssn_last4` (string, required, nullable) — The last four digits of the employee's social security number printed in box a of the first statement. ### W2ReportData_W2Metadata How the file was read. - `form_key` (string, required) — The form's key, w2. - `detected_year` (integer, required, nullable) — The tax year the form was printed for. - `parent_form` (string, required, nullable) — Null on a form uploaded on its own. - `faces_read` (integer, required) — The number of statement faces printed across the upload, every copy counted, on a Form W-2. - `copies_collapsed` (integer, required) — The number of printed faces that repeat another face of the same statement, on a Form W-2. - `w2_count` (integer, required) — The number of distinct statements the upload prints, one per employer, on a Form W-2. - `base_page` (integer, optional) — The page of the uploaded file the form starts on, counting from zero. - `layout` (enum, optional) — The printing of the first statement on a Form W-2: irs_1up, the IRS form with one statement per page; irs_4up, the four-per-page sheet; substitute, a payroll or preparer print. - Allowed values: `irs_1up`, `irs_4up`, `substitute` - `rescued_fields` (list of string, optional) — The boxes whose figure the page-level read supplied rather than the box itself, on a Form W-2; absent when every figure was read from its box. - `standalone` (boolean, optional) — True on a form uploaded on its own. ### W2ReportDataDepreciationReports Always null on a Form W-2. ### W2ReportData_W2Box12Item One box 12 entry of a Form W-2. - `code` (string, required, nullable) — The one or two letter code printed beside the amount. - `amount` (string, required, nullable) — The amount printed for the code. - `slot` (string, optional, nullable) — The letter of the box 12 line the entry is printed on, a through d, when the form letters its box 12 lines; null when the form prints one box 12 caption. ### W2ReportData_W2Box14Item One box 14 entry of a Form W-2. - `label` (string, required, nullable) — The label the employer printed. - `amount` (string, required, nullable) — The amount printed beside the label. ### W2ReportData_W2StateRow One state row of a Form W-2, boxes 15 through 17. - `state` (string, required, nullable) — Box 15, the state. - `employer_state_id` (string, required, nullable) — Box 15, employer's state ID number. - `box_16_state_wages` (string, required, nullable) — Box 16, state wages, tips, etc. - `box_17_state_tax` (string, required, nullable) — Box 17, state income tax. ### W2ReportData_W2LocalRow One local row of a Form W-2, boxes 18 through 20. - `box_18_local_wages` (string, required, nullable) — Box 18, local wages, tips, etc. - `box_19_local_tax` (string, required, nullable) — Box 19, local income tax. - `box_20_locality` (string, required, nullable) — Box 20, locality name. ### W2ReportData_FormW2 Form W-2, Wage and Tax Statement, one employer's statement of one employee's wages and withholding for one year. - `copy` (string, required, nullable) — The copy letter printed on the form (A, B, C, D, 1 or 2), when the print carries one. - `tax_year` (integer, required, nullable) — The tax year printed beside the form title. - `control_number` (string, required, nullable) — Box d, control number, as printed. - `employer_ein` (string, required, nullable) — Box b, employer identification number, masked to the last four digits. - `employer_name` (string, required, nullable) — Box c, the employer's name. - `employer_address` (string, required, nullable) — Box c, the employer's address below the name, on one line. - `employee_name` (string, required, nullable) — Box e, the employee's first name, initial and last name, as printed. - `employee_ssn_last4` (string, required, nullable) — Box a, the last four digits of the employee's social security number; the rest of the number is never served. - `box_1_wages` (string, required, nullable) — Box 1, wages, tips, other compensation. - `box_2_federal_tax_withheld` (string, required, nullable) — Box 2, federal income tax withheld. - `box_3_ss_wages` (string, required, nullable) — Box 3, social security wages. - `box_4_ss_tax_withheld` (string, required, nullable) — Box 4, social security tax withheld. - `box_5_medicare_wages` (string, required, nullable) — Box 5, Medicare wages and tips. - `box_6_medicare_tax_withheld` (string, required, nullable) — Box 6, Medicare tax withheld. - `box_7_ss_tips` (string, required, nullable) — Box 7, social security tips. - `box_8_allocated_tips` (string, required, nullable) — Box 8, allocated tips. - `box_10_dependent_care_benefits` (string, required, nullable) — Box 10, dependent care benefits. - `box_11_nonqualified_plans` (string, required, nullable) — Box 11, nonqualified plans. - `box_12` (list of W2ReportData_W2Box12Item, required) — Box 12, one entry per printed code and amount, 12a through 12d. - `box_13_statutory_employee` (boolean, required, nullable) — Box 13, the statutory employee box, true when checked. - `box_13_retirement_plan` (boolean, required, nullable) — Box 13, the retirement plan box, true when checked. - `box_13_third_party_sick_pay` (boolean, required, nullable) — Box 13, the third-party sick pay box, true when checked. - `box_14_other` (list of W2ReportData_W2Box14Item, required) — Box 14, other, one entry per printed label and amount. - `box_14b_tipped_occupation_codes` (list of string, required) — Box 14b, Treasury tipped occupation codes, on a form that prints the box. - `state_rows` (list of W2ReportData_W2StateRow, required) — Boxes 15 through 17, one row per state. - `local_rows` (list of W2ReportData_W2LocalRow, required) — Boxes 18 through 20, one row per locality. - `omb_number` (string, required, nullable) — The OMB number printed on the form, 1545-0008 or 1545-0029. - `layout` (enum, required) — The printing of the statement: irs_1up, the IRS form with one statement per page; irs_4up, the four-per-page sheet; substitute, a payroll or preparer print. - Allowed values: `irs_1up`, `irs_4up`, `substitute` - `source_pages` (list of integer, required) — The pages of the uploaded file the statement is printed on, counting from one; several when the upload repeats it. - `rescued_fields` (list of string, required) — The boxes whose figure was read from the page as a whole rather than from the box itself; empty when every figure was read from its box. ## Examples **Response** ```json { "borrower_id": "3f9c2b1e8d7a4c5b9e0f1a2b", "forms": [ { "extracted_document_id": "7a1d4e9c2b3f4a5d8e6c1b0f", "document_category": "w2", "report_data": { "form": "w2", "data": { "copy": "B", "tax_year": 2025, "control_number": "A-1001", "employer_ein": "XX-XXX0123", "employer_name": "Northfield Supply LLC", "employer_address": "100 Harbor Way, Riverton, OH 43000", "employee_name": "Ada Marsh", "employee_ssn_last4": "1234", "box_1_wages": "51400.00", "box_2_federal_tax_withheld": "6240.00", "box_3_ss_wages": "54000.00", "box_4_ss_tax_withheld": "3348.00", "box_5_medicare_wages": "54000.00", "box_6_medicare_tax_withheld": "783.00", "box_7_ss_tips": null, "box_8_allocated_tips": null, "box_10_dependent_care_benefits": "1200.00", "box_11_nonqualified_plans": null, "box_12": [ { "code": "D", "amount": "2600.00", "slot": "a" }, { "code": "DD", "amount": "8400.00", "slot": "b" } ], "box_13_statutory_employee": false, "box_13_retirement_plan": true, "box_13_third_party_sick_pay": false, "box_14_other": [ { "label": "SDI", "amount": "468.00" }, { "label": "UNION DUES", "amount": "300.00" } ], "box_14b_tipped_occupation_codes": [], "state_rows": [ { "state": "OH", "employer_state_id": "OH-0000123", "box_16_state_wages": "54000.00", "box_17_state_tax": "1620.00" }, { "state": "PA", "employer_state_id": "PA-0000456", "box_16_state_wages": "2000.00", "box_17_state_tax": "60.00" } ], "local_rows": [ { "box_18_local_wages": "54000.00", "box_19_local_tax": "540.00", "box_20_locality": "RIVERTON" } ], "omb_number": "1545-0008", "layout": "irs_1up", "source_pages": [ 1 ], "rescued_fields": [], "forms_w2": [ { "copy": "B", "tax_year": 2025, "control_number": "A-1001", "employer_ein": "XX-XXX0123", "employer_name": "Northfield Supply LLC", "employer_address": "100 Harbor Way, Riverton, OH 43000", "employee_name": "Ada Marsh", "employee_ssn_last4": "1234", "box_1_wages": "51400.00", "box_2_federal_tax_withheld": "6240.00", "box_3_ss_wages": "54000.00", "box_4_ss_tax_withheld": "3348.00", "box_5_medicare_wages": "54000.00", "box_6_medicare_tax_withheld": "783.00", "box_7_ss_tips": null, "box_8_allocated_tips": null, "box_10_dependent_care_benefits": "1200.00", "box_11_nonqualified_plans": null, "box_12": [ { "code": "D", "amount": "2600.00", "slot": "a" }, { "code": "DD", "amount": "8400.00", "slot": "b" } ], "box_13_statutory_employee": false, "box_13_retirement_plan": true, "box_13_third_party_sick_pay": false, "box_14_other": [ { "label": "SDI", "amount": "468.00" }, { "label": "UNION DUES", "amount": "300.00" } ], "box_14b_tipped_occupation_codes": [], "state_rows": [ { "state": "OH", "employer_state_id": "OH-0000123", "box_16_state_wages": "54000.00", "box_17_state_tax": "1620.00" }, { "state": "PA", "employer_state_id": "PA-0000456", "box_16_state_wages": "2000.00", "box_17_state_tax": "60.00" } ], "local_rows": [ { "box_18_local_wages": "54000.00", "box_19_local_tax": "540.00", "box_20_locality": "RIVERTON" } ], "omb_number": "1545-0008", "layout": "irs_1up", "source_pages": [ 1 ], "rescued_fields": [] } ], "taxpayer_name": "Ada Marsh", "ssn_last4": "1234" }, "metadata": { "form_key": "w2", "detected_year": 2025, "parent_form": null, "faces_read": 1, "copies_collapsed": 0, "w2_count": 1, "base_page": 0, "layout": "irs_1up", "standalone": true }, "k1_partners": [], "statements": [], "depreciation_reports": null } } ] } ``` **SDK Code** ```python import requests url = "https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s" headers = {"Authorization": "Bearer "} response = requests.get(url, headers=headers) print(response.json()) ``` ```javascript const url = 'https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s'; const options = {method: 'GET', headers: {Authorization: 'Bearer '}}; try { const response = await fetch(url, options); const data = await response.json(); console.log(data); } catch (error) { console.error(error); } ``` ```go package main import ( "fmt" "net/http" "io" ) func main() { url := "https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s" req, _ := http.NewRequest("GET", url, nil) req.Header.Add("Authorization", "Bearer ") res, _ := http.DefaultClient.Do(req) defer res.Body.Close() body, _ := io.ReadAll(res.Body) fmt.Println(res) fmt.Println(string(body)) } ``` ```ruby require 'uri' require 'net/http' url = URI("https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s") http = Net::HTTP.new(url.host, url.port) http.use_ssl = true request = Net::HTTP::Get.new(url) request["Authorization"] = 'Bearer ' response = http.request(request) puts response.read_body ``` ```java import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.Unirest; HttpResponse response = Unirest.get("https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s") .header("Authorization", "Bearer ") .asString(); ``` ```php request('GET', 'https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s', [ 'headers' => [ 'Authorization' => 'Bearer ', ], ]); echo $response->getBody(); ``` ```csharp using RestSharp; var client = new RestClient("https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s"); var request = new RestRequest(Method.GET); request.AddHeader("Authorization", "Bearer "); IRestResponse response = client.Execute(request); ``` ```swift import Foundation let headers = ["Authorization": "Bearer "] let request = NSMutableURLRequest(url: NSURL(string: "https://api.spreadspace.app/api/borrowers/3f9c2b1e8d7a4c5b9e0f1a2b/extractions/w2s")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in if (error != nil) { print(error as Any) } else { let httpResponse = response as? HTTPURLResponse print(httpResponse) } }) dataTask.resume() ```