# Business Made · Filings

Part of AppEngine API Documentation. Full index: https://appengine.appmint.io/documentation.md
## POST /business-made/payroll/tax-forms/w2/{employeeId}/{taxYear}

**Generate a W-2**

`operationId: PayrollConfigController_generateW2`

Generates an employee's W-2 for a tax year from their processed runs. Reconcile against the payroll summary first — a W-2 issued with wrong figures has to be corrected on a W-2c.

#### Signature

```http
POST /business-made/payroll/tax-forms/w2/{employeeId}/{taxYear} (employeeId: string, taxYear: string, regenerate?: string) -> The generated W-2
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Correcting an issued W-2 means filing a W-2c — check the figures before generating.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/reports/w2/{employeeId}/{year}`
- `POST /business-made/payroll/filings/w3/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `employeeId` | path | string | yes | Employee id. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated W-2 |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/tax-forms/1099-nec/{contractorId}/{taxYear}

**Generate a 1099-NEC**

`operationId: PayrollConfigController_generate1099Nec`

Generates a 1099-NEC for a contractor for a tax year. Contractors are reported separately from employees — someone misclassified will appear on the wrong form.

#### Signature

```http
POST /business-made/payroll/tax-forms/1099-nec/{contractorId}/{taxYear} (contractorId: string, taxYear: string, regenerate?: string) -> The generated 1099-NEC
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/filings/1096/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `contractorId` | path | string | yes | Contractor id. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated 1099-NEC |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/tax-forms/year-end/{taxYear}

**Generate all year-end forms**

`operationId: PayrollConfigController_generateYearEnd`

Generates the full set of year-end forms for a tax year in one operation — every W-2 and 1099-NEC. Run the payroll summary and readiness checks first; this is the point errors become filed documents.

#### Signature

```http
POST /business-made/payroll/tax-forms/year-end/{taxYear} (taxYear: string, regenerate?: string) -> The generation result
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Check `GET /business-made/payroll/employer-setup/readiness` before running.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/tax-forms`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generation result |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/payroll/tax-forms

**List tax forms**

`operationId: PayrollConfigController_listTaxForms`

The tax forms generated for the org, with their year and status.

#### Signature

```http
GET /business-made/payroll/tax-forms (taxYear?: string, type?: string) -> Tax forms
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/tax-forms/{formId}/download`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | query | string | — |  |
| `type` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | Tax forms |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/payroll/tax-forms/{formId}/download

**Download a tax form**

`operationId: PayrollConfigController_downloadTaxForm`

Downloads a generated tax form. These contain full earnings and identifying details — restrict access accordingly.

#### Signature

```http
GET /business-made/payroll/tax-forms/{formId}/download (formId: string) -> The form document
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/tax-forms`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `formId` | path | string | yes | Form id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The form document |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/941/{taxYear}/{quarter}

**Generate Form 941**

`operationId: PayrollConfigController_generate941`

Employer's Quarterly Federal Tax Return for a year and quarter — the return reconciling federal tax withheld against deposits made. Generated from processed runs, so unprocessed payroll is simply absent from it.

#### Signature

```http
POST /business-made/payroll/filings/941/{taxYear}/{quarter} (taxYear: string, quarter: string, regenerate?: string) -> The generated 941
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Only processed runs contribute. Confirm the quarter is closed before generating.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/filings/940/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `quarter` | path | string | yes | Calendar quarter, 1–4. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated 941 |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/940/{taxYear}

**Generate Form 940**

`operationId: PayrollConfigController_generate940`

Employer's Annual FUTA Tax Return for a year — federal unemployment tax. Annual rather than quarterly.

#### Signature

```http
POST /business-made/payroll/filings/940/{taxYear} (taxYear: string, regenerate?: string) -> The generated 940
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/filings/941/{taxYear}/{quarter}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated 940 |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/w3/{taxYear}

**Generate Form W-3**

`operationId: PayrollConfigController_generateW3`

Transmittal of Wage and Tax Statements — **sums the year's W-2s**. Generate the W-2s first: the W-3 totals whatever exists, so a missing W-2 produces a transmittal that understates the year.

#### Signature

```http
POST /business-made/payroll/filings/w3/{taxYear} (taxYear: string, regenerate?: string) -> The generated W-3
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Depends on the W-2s already existing. Generate year-end forms first.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/tax-forms/year-end/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated W-3 |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/efw2/{taxYear}

**Build the SSA EFW2 W-2 file**

`operationId: PayrollConfigController_generateEfw2`

Builds the SSA EFW2 wage file (Publication 42-007) from the year's W-2s — the file the owner validates in AccuWage Online and uploads to Business Services Online. Fixed-width 512-byte records: RA submitter, RE employer, RW per employee, RO when an optional amount exists, RS per state with wage data, RT/RU/RV totals, RF final. Recorded as an e-file submission (agency `ssa`, program `efw2`, env `file`): status `ready` with the stored file, or `error` with the list of problems and no file.

#### Signature

```http
POST /business-made/payroll/filings/efw2/{taxYear} (taxYear: string, regenerate?: string) -> { submission, fileName, recordCount, errors, totals } — the file text is never returned (it holds full SSNs)
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- Needs the BSO User ID in the employer setup (`bsoUserId`), plus contact name, phone and e-mail — the generator returns `EFW2_BSO_USER_ID_MISSING` without it.
- Returns the latest ready file for the year unless `regenerate=true`.
- Generate the W-2s first; the file reports whatever W-2s exist.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/filings/efw2/{taxYear}/download`
- `POST /business-made/payroll/filings/w3/{taxYear}`
- `GET /business-made/efile/submissions`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | { submission, fileName, recordCount, errors, totals } — the file text is never returned (it holds full SSNs) |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/payroll/filings/efw2/{taxYear}/download

**Download the SSA EFW2 W-2 file**

`operationId: PayrollConfigController_downloadEfw2`

Downloads the latest ready EFW2 file for the year (or the one named by `submissionId`) as plain text, CR/LF-delimited, ready for AccuWage and BSO upload. Contains full SSNs — restrict access accordingly.

#### Signature

```http
GET /business-made/payroll/filings/efw2/{taxYear}/download (taxYear: string, submissionId?: string) -> The EFW2 file
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/filings/efw2/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `submissionId` | query | string | — |  |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The EFW2 file |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/1096/{taxYear}

**Generate Form 1096**

`operationId: PayrollConfigController_generate1096`

Annual Summary and Transmittal — **sums the year's 1099-NECs**. Same dependency as the W-3: generate the 1099s first or the totals will be short.

#### Signature

```http
POST /business-made/payroll/filings/1096/{taxYear} (taxYear: string, regenerate?: string) -> The generated 1096
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `POST /business-made/payroll/tax-forms/1099-nec/{contractorId}/{taxYear}`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated 1096 |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## POST /business-made/payroll/filings/state-quarterly/{taxYear}/{quarter}/{state}

**Generate a state quarterly wage report**

`operationId: PayrollConfigController_generateStateQuarterly`

The state quarterly wage report for a year, quarter and state. One filing per state you have employees in — check the coverage report so no state is missed.

#### Signature

```http
POST /business-made/payroll/filings/state-quarterly/{taxYear}/{quarter}/{state} (taxYear: string, quarter: string, state: string, regenerate?: string) -> The generated report
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Notes

- A state with employees but no filing is a missed obligation — reconcile against `tax-rules/coverage`.

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/tax-rules/coverage`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `taxYear` | path | string | yes | Tax year. |
| `quarter` | path | string | yes | Calendar quarter, 1–4. |
| `state` | path | string | yes | State code. |
| `regenerate` | query | string | — | Force a fresh generation instead of returning the cached document. Send `true`. |

### Responses

| Status | Meaning |
| --- | --- |
| `201` | The generated report |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

## GET /business-made/payroll/filings/{formId}/download

**Download a filing**

`operationId: PayrollConfigController_downloadFiling`

Downloads a generated statutory filing, ready for submission.

#### Signature

```http
GET /business-made/payroll/filings/{formId}/download (formId: string) -> The filing document
```

#### Access

Requires a bearer JWT (`Authorization: Bearer <token>`).

#### Errors

Plus the standard platform errors: `401`, `403`, `429`, `500`.

#### See also

- `GET /business-made/payroll/tax-forms`

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `orgid` | header | string | yes | Organization (tenant) identifier. Every request is scoped to this org; data from other orgs is never visible. Issued with your API credentials. |
| `formId` | path | string | yes | Filing id. |

### Responses

| Status | Meaning |
| --- | --- |
| `200` | The filing document |
| `401` | Authentication failed: Invalid or expired token — The `Authorization` header is missing, malformed, or the JWT has expired. |
| `403` | You do not have permission to perform this action — The caller is authenticated but lacks the role required by the endpoint, or is acting on another org. |
| `429` | Too Many Requests — More than 100,000 requests from one IP within 5 minutes (configurable per deployment). CORS preflights and requests from inside the platform cluster are not counted. The limiter answers before the error filter, so the body is `{ statusCode, error, message }` with no `path`, `method` or `timeStamp`; the `RateLimit-*` response headers say when the window resets. |
| `500` | An unexpected error occurred. Our team has been notified. — An unhandled server-side failure. |

