# Example: hosted endpoints document

Doc gen writes `docs/application/hosted-endpoints.md` for a web front end that
hosts requests for its own screens: named page handlers that return JSON, a
partial view or a file, grid reads and updates, and any API controller or
minimal API the application serves to itself. These are not a published API, so
there is no `docs/apis/` set; each endpoint is listed once on this page and the
screens link to it. The example is for an ASP.NET Core Razor Pages front end;
the document for a .NET Framework 4 MVC front end has the same shape (see the
checks below).

## What reviewers should check

- **The page exists only when there is something to list.** The default `OnGet`
  or `OnPost` handler that renders a screen is the screen, not an endpoint. A
  page with no hosted endpoints should not have this document.
- **Every H3 is a plain-text anchor.** `### GET /Policy/Summary?handler=Declaration`
  has no backticks, so the anchor is `#get-policysummaryhandlerdeclaration`.
  The `AJAX and grid actions` tables on the screen pages link to exactly these
  anchors.
- **Both directions reconcile.** Each row in a screen's
  `## AJAX and grid actions` table has an entry here, and each entry's
  `Called from` links back to a screen page. An endpoint that no screen reaches is marked `unattributed **`
  rather than dropped. The `Summary` counts add up to the number of entries.
- **Requests use the Core form.** The H3 and `URL` row use
  `VERB /<Page>?handler=<Name>`, and the `Handler` row names the page model
  method (`SummaryModel.OnGetDeclarationAsync`). A `Controller.Action` here
  means the MVC vocabulary leaked in.
- **Anti-forgery is stated per endpoint.** POST handlers say whether the token
  is validated and why; GET handlers say it does not apply.
- **Access is the declared requirement.** `Authorization` names the attribute
  and the type that declares it, and a requirement contributed by a package base
  class carries `†`.
- **The same page applies to .NET Framework 4 MVC apps.** The
  `net4-app-hosted-endpoints.md` template uses `### <VERB> <Controller>/<Action>`
  headings, a `Controller.Action` row instead of `Handler`, a
  `[SaifAuthorize(Roles = "...")]` authorization row, and no anti-forgery row.
  Its kinds are Web API, grid, AJAX, and remote validator.

## Example

The document below is a complete, correct `hosted-endpoints.md` for the same
fictional `SAIF.Policy.Portal` application as the
[Razor Pages screen example](ncore-screen.md).

[View rendered example](rendered/application/hosted-endpoints.md) — the same document as a real page, so you can compare rendering as well as source.

````markdown
---
title: Hosted endpoints
summary: Named page handlers, partial fetches and API actions the application exposes to its own screens.
status: draft
owner: Policy Services Team
last_reviewed: 2026-09-09
---

# Hosted endpoints

These endpoints serve this application's own screens and are not a published API. They are listed here once so that each screen page can link to the request it makes.

## Endpoint catalog

### POST /Payroll/Reports?handler=Read

| Field | Value |
| --- | --- |
| Handler | `ReportsModel.OnPostReadAsync` |
| Kind | grid read |
| URL | `/Payroll/Reports?handler=Read` |
| Request | Form fields of the Kendo `DataSourceRequest` (`page`, `pageSize`, `sort`, `filter`) and the `policyNumber` route value |
| Response | `JsonResult` wrapping a `DataSourceResult` of `PayrollReportRow` |
| Anti-forgery | Validated by default; the grid `data` function sends the request verification token |
| Authorization | `[SecurityApiAuthorize("PolicyServices.Read,PolicyServices.Underwriting")]` declared on `BolPolicyModel`† |
| Called from | [Payroll Reports](../screens/payroll-reports.md) |

### GET /Policy/Search?handler=Employers

| Field | Value |
| --- | --- |
| Handler | `SearchModel.OnGetEmployersAsync` |
| Kind | named handler JSON |
| URL | `/Policy/Search?handler=Employers` |
| Request | Query string `term` (`string`, at least three characters) |
| Response | `JsonResult` array of `{ employerId, employerName, policyNumber }`; an empty array when `term` is shorter than three characters |
| Anti-forgery | Not applicable; GET handlers are not validated |
| Authorization | `[SecurityApiAuthorize("PolicyServices.Read,PolicyServices.Underwriting")]` declared on `SearchModel` |
| Called from | [Policy Search](../screens/policy-search.md) |

### GET /Policy/Summary?handler=Declaration

| Field | Value |
| --- | --- |
| Handler | `SummaryModel.OnGetDeclarationAsync` |
| Kind | file download |
| URL | `/Policy/Summary?handler=Declaration` |
| Request | Optional route value `policyNumber`; the policy number in `WebContext` is used when it is absent |
| Response | `FileStreamResult`, `application/pdf` |
| Anti-forgery | Not applicable; GET handlers are not validated |
| Authorization | `[SecurityApiAuthorize("PolicyServices.Read,PolicyServices.Underwriting")]` declared on `BolPolicyModel`† |
| Called from | [Policy Summary](../screens/policy-summary.md) |

### GET /Policy/Summary?handler=PayrollHistory

| Field | Value |
| --- | --- |
| Handler | `SummaryModel.OnGetPayrollHistoryAsync` |
| Kind | partial fetch |
| URL | `/Policy/Summary?handler=PayrollHistory` |
| Request | Query string `reportYear` (`int`, bound to `ReportYear`) |
| Response | `PartialViewResult` for `_PayrollHistory`; `400 Bad Request` when `reportYear` is not a year in the policy history |
| Anti-forgery | Not applicable; GET handlers are not validated |
| Authorization | `[SecurityApiAuthorize("PolicyServices.Read,PolicyServices.Underwriting")]` declared on `BolPolicyModel`† |
| Called from | [Policy Summary](../screens/policy-summary.md) |

## Summary

| Kind | Count |
| --- | --- |
| Named handler (JSON) | 1 |
| Named handler (partial) | 1 |
| File download | 1 |
| API controller / minimal API | 0 |
| Grid | 1 |
| Unattributed | 0 |

---

> [!NOTE]
> Statements marked with `*` are inferred from code patterns. Statements marked with `**` could not be verified from available source. Statements marked with `†` are sourced from package documentation retrieved with the Legends CLI.

## Related documentation
- [Application index](index.md)
- [Architecture](architecture.md)
- [Security and authorization](security-authorization.md)
- [Screen catalog](../screens/index.md)

## Sources
- src/SAIF.Policy.Portal/Pages/Payroll/Reports.cshtml.cs
- src/SAIF.Policy.Portal/Pages/Policy/Search.cshtml.cs
- src/SAIF.Policy.Portal/Pages/Policy/Summary.cshtml.cs
````
