Implement Endpoint
Implement one FreeAgent endpoint page end-to-end for this repository, including SDK models and wrappers, service methods, tests, sample app page and navigation sync, and README/API coverage updates.
If the entity already exists, retrofit it to current guardrails in the same run.
Required Inputs
EntityName (required)
DocsUrlOverride (optional FreeAgent docs URL)
Step 1 — Validate Entity and Inventory Operations
- Resolve the docs index: https://dev.freeagent.com/docs/index
- Validate that
EntityName maps to a real docs page.
- If no matching endpoint page exists, stop immediately and report the invalid entity.
- If
DocsUrlOverride is provided, validate and use that page.
- Fetch the docs page and list every operation heading (
## / ###) before planning — for example "List all categories", "Get a single category", "Create an income category", "Create a cost of sales category", "Update an admin expenses category". The unit of implementation is the documented operation heading, not the HTTP route alone.
Step 2 — Plan First (New or Retrofit)
- Produce a concise implementation plan before editing code.
- If the entity already exists, audit existing models and services against these guardrails:
- Every serialised property has
JsonPropertyName
- Date-only API fields use
DateOnly (not DateTime)
- Timestamp fields use
DateTimeOffset (not DateTime)
- Constrained string fields are enums or strong value mappings with exact wire values
- Response payloads use explicit wrapper/envelope models
- Services validate wrappers and throw
FreeAgentApiException on missing payload
- Flag any guardrail violations as retrofit tasks in the plan.
- Include in the plan:
- Operation heading inventory from Step 1
- A table mapping heading → HTTP route → SDK method → request type → allowed fields (new) or existing service gaps (retrofit)
- Documented use-case variants — when the API docs describe multiple create/update shapes for the same route (for example income vs cost-of-sales categories), list each variant and the typed SDK method/request type it will map to
- New files vs retrofit files (with specific violations listed)
- Breaking API-surface changes expected
- Test, sample app, and documentation changes
Proceed to implementation only after the plan is complete.
Step 3 — Models and Guardrails
Apply to all new and retrofitted models:
- Use
System.Text.Json.
- Every serialised/deserialised property must have
JsonPropertyName.
- Use
DateOnly for date-only API fields.
- Use
DateTimeOffset for timestamp fields (not DateTime).
- Constrained string fields must use enums or strong value mappings with exact wire-value behaviour.
- API-facing enums must use explicit
JsonStringEnumMemberName wire values for each enum member.
- When docs are ambiguous for constrained values, do not silently guess; mark unresolved mapping and add a follow-up issue.
- Response payloads must use explicit wrapper/envelope models.
- Missing required payload branches must throw
FreeAgentApiException.
- Per-variant allowed values: when allowed wire keys differ by operation variant, use a distinct enum on that request only. When they also differ by a documented discriminator (for example company type), use discriminator-specific enums and factory methods — do not flatten into one enum, do not leave
string plus "see the API docs", and do not add a runtime validator that fetches Company or account settings. See adr-0010-documented-operations-to-sdk-methods.md.
Common retrofit violations:
DateTime instead of DateOnly for date-only fields
DateTime instead of DateTimeOffset for timestamps
- String fields that should be enums per API docs
- Missing
JsonPropertyName
- Response wrappers not validated in service methods
- Generic create/update payload that unions all variant attributes
Step 4 — Services and Pagination
- Follow existing service structure under
src/FreeAgent.Client/Services/.
- Keep methods async and accept
CancellationToken.
- When the API paginates list results, provide both single-page and auto-pagination methods. Do not invent pagination for endpoints that return a complete collection (for example Categories).
- Where the API accepts
per_page, respect the FreeAgent maximum of 100 and fail fast if the caller exceeds it.
- Documented use-case variants: when the API docs describe multiple create or update shapes for the same HTTP route, expose a separate public request type and service method per variant (for example
CreateIncomeCategoryAsync, CreateCostOfSalesCategoryAsync). Each request type must include only the attributes allowed for that variant. Fixed wire values such as category_group are set by the SDK — callers must not supply them. Do not expose a single generic create/update that forces consumers to read external docs to learn which fields apply.
- Documented local contract checks: fail fast only on constraints the official docs state that do not require account state. Do not invent extra validation, uniqueness checks, or fetches of Company/settings. Categories nominal-code ranges are one documented example, not a pattern to copy onto undocumented fields.
Step 5 — Tests
Add or update tests to cover:
- URL construction
- Envelope/wrapper deserialisation
- Date handling (
DateOnly)
- Enum/string wire mapping exactness
- Missing payload branch exceptions
- Pagination behaviour and cancellation when the API paginates
- At least one test per documented write variant — assert URL, envelope, and which fields are included or excluded in the serialised payload
Step 6 — Sample App Sync
Follow the probe-page standard documented in docs/contributing/sample-probe-pages.md. Use Company (single GET), Contacts (paginated list + CRUD), and Categories (non-paginated list + multi-variant writes) as reference implementations.
- Add or update page(s) under
samples/FreeAgent.Client.BlazorSample/Components/Pages/.
- Update navigation in
samples/FreeAgent.Client.BlazorSample/Components/Layout/MainLayout.razor.
- Do not add sample UI for endpoints not implemented in SDK.
- On each probe page, include:
EndpointProbeHeader (call under test, DocsUrl, environment, endpoint path)
ModelProbeResults built via ModelWireDiagnostics.Build(...) after successful SDK calls
ApiErrorDiagnostics on failures
- A readable raw JSON section (provided by
ModelProbeResults)
- For list endpoints: per-row mapping inspection from the wire array item (see
Contacts.razor).
- For CRUD endpoints: detail page with
?id= deep links; fetch wire JSON after create/update; show MudProgressLinear while operations run (see ContactDetail.razor).
- When the SDK exposes multiple write variants for the same resource, the sample must be able to invoke each public write method — a variant selector on one CRUD page is sufficient; exercising only one variant (for example income-only) is not.
- Add seed fixtures when demo data helps field coverage (narrative canon and/or a full-detail probe contact); upsert by a stable natural key when re-running should refresh existing records.
- Only model wire fields that appear in the official FreeAgent API docs.
Update samples/README.md and docs/reference/api-coverage.md in the same change.
Step 7 — Documentation
Update the root README.md, src/FreeAgent.Client/README.md (API coverage, usage examples), docs/reference/api-coverage.md, and any affected plan or entity-map sequencing docs.
Step 8 — Validation
Run from repository root:
dotnet build
dotnet test
Highlight any breaking changes applied during retrofit (DateTime → DateOnly, string → enum).
References
adr/adr-0010-documented-operations-to-sdk-methods.md
docs/contributing/sample-probe-pages.md
plan/IMPLEMENTING_ENDPOINTS.md
plan/API_TYPE_MAPPING_POLICY.md
plan/API_TO_SDK_ALIGNMENT.md
CONVENTIONS.md
AGENTS.md
1---2name: implement-endpoint3description: Implement or retrofit one FreeAgent endpoint end-to-end with strict model guardrails, sample app sync, and plan-first workflow. Use when adding or updating SDK resource services, models, tests, or sample pages for a FreeAgent API entity.4---56# Implement Endpoint78Implement one FreeAgent endpoint page end-to-end for this repository, including SDK models and wrappers, service methods, tests, sample app page and navigation sync, and README/API coverage updates.910If the entity already exists, retrofit it to current guardrails in the same run.1112## Required Inputs1314- `EntityName` (required)15- `DocsUrlOverride` (optional FreeAgent docs URL)1617## Step 1 — Validate Entity and Inventory Operations18191. Resolve the docs index: https://dev.freeagent.com/docs/index202. Validate that `EntityName` maps to a real docs page.213. If no matching endpoint page exists, stop immediately and report the invalid entity.224. If `DocsUrlOverride` is provided, validate and use that page.235. **Fetch the docs page and list every operation heading** (`##` / `###`) before planning — for example "List all categories", "Get a single category", "Create an income category", "Create a cost of sales category", "Update an admin expenses category". The unit of implementation is the **documented operation heading**, not the HTTP route alone.2425## Step 2 — Plan First (New or Retrofit)26271. Produce a concise implementation plan before editing code.282. If the entity already exists, audit existing models and services against these guardrails:29 - Every serialised property has `JsonPropertyName`30 - Date-only API fields use `DateOnly` (not `DateTime`)31 - Timestamp fields use `DateTimeOffset` (not `DateTime`)32 - Constrained string fields are enums or strong value mappings with exact wire values33 - Response payloads use explicit wrapper/envelope models34 - Services validate wrappers and throw `FreeAgentApiException` on missing payload353. Flag any guardrail violations as retrofit tasks in the plan.364. Include in the plan:37 - **Operation heading inventory** from Step 138 - A table mapping **heading → HTTP route → SDK method → request type → allowed fields** (new) or existing service gaps (retrofit)39 - **Documented use-case variants** — when the API docs describe multiple create/update shapes for the same route (for example income vs cost-of-sales categories), list each variant and the typed SDK method/request type it will map to40 - New files vs retrofit files (with specific violations listed)41 - Breaking API-surface changes expected42 - Test, sample app, and documentation changes4344Proceed to implementation only after the plan is complete.4546## Step 3 — Models and Guardrails4748Apply to all new and retrofitted models:49501. Use `System.Text.Json`.512. Every serialised/deserialised property must have `JsonPropertyName`.523. Use `DateOnly` for date-only API fields.534. Use `DateTimeOffset` for timestamp fields (not `DateTime`).545. Constrained string fields must use enums or strong value mappings with exact wire-value behaviour.556. API-facing enums must use explicit `JsonStringEnumMemberName` wire values for each enum member.567. When docs are ambiguous for constrained values, do not silently guess; mark unresolved mapping and add a follow-up issue.578. Response payloads must use explicit wrapper/envelope models.589. Missing required payload branches must throw `FreeAgentApiException`.5910. **Per-variant allowed values:** when allowed wire keys differ by operation variant, use a distinct enum on that request only. When they also differ by a documented discriminator (for example company type), use discriminator-specific enums and factory methods — do not flatten into one enum, do not leave `string` plus "see the API docs", and do not add a runtime validator that fetches Company or account settings. See [adr-0010-documented-operations-to-sdk-methods.md](../../adr/adr-0010-documented-operations-to-sdk-methods.md).6061Common retrofit violations:6263- `DateTime` instead of `DateOnly` for date-only fields64- `DateTime` instead of `DateTimeOffset` for timestamps65- String fields that should be enums per API docs66- Missing `JsonPropertyName`67- Response wrappers not validated in service methods68- Generic create/update payload that unions all variant attributes6970## Step 4 — Services and Pagination71721. Follow existing service structure under `src/FreeAgent.Client/Services/`.732. Keep methods async and accept `CancellationToken`.743. When the API paginates list results, provide both single-page and auto-pagination methods. Do not invent pagination for endpoints that return a complete collection (for example Categories).754. Where the API accepts `per_page`, respect the FreeAgent maximum of 100 and fail fast if the caller exceeds it.765. **Documented use-case variants:** when the API docs describe multiple create or update shapes for the same HTTP route, expose a separate public request type and service method per variant (for example `CreateIncomeCategoryAsync`, `CreateCostOfSalesCategoryAsync`). Each request type must include only the attributes allowed for that variant. Fixed wire values such as `category_group` are set by the SDK — callers must not supply them. Do not expose a single generic create/update that forces consumers to read external docs to learn which fields apply.776. **Documented local contract checks:** fail fast only on constraints the official docs state that do not require account state. Do not invent extra validation, uniqueness checks, or fetches of Company/settings. Categories nominal-code ranges are one documented example, not a pattern to copy onto undocumented fields.7879## Step 5 — Tests8081Add or update tests to cover:8283- URL construction84- Envelope/wrapper deserialisation85- Date handling (`DateOnly`)86- Enum/string wire mapping exactness87- Missing payload branch exceptions88- Pagination behaviour and cancellation **when the API paginates**89- **At least one test per documented write variant** — assert URL, envelope, and which fields are included or excluded in the serialised payload9091## Step 6 — Sample App Sync9293Follow the probe-page standard documented in [`docs/contributing/sample-probe-pages.md`](../../docs/contributing/sample-probe-pages.md). Use **Company** (single GET), **Contacts** (paginated list + CRUD), and **Categories** (non-paginated list + multi-variant writes) as reference implementations.94951. Add or update page(s) under `samples/FreeAgent.Client.BlazorSample/Components/Pages/`.962. Update navigation in `samples/FreeAgent.Client.BlazorSample/Components/Layout/MainLayout.razor`.973. Do not add sample UI for endpoints not implemented in SDK.984. On each probe page, include:99 - `EndpointProbeHeader` (call under test, `DocsUrl`, environment, endpoint path)100 - `ModelProbeResults` built via `ModelWireDiagnostics.Build(...)` after successful SDK calls101 - `ApiErrorDiagnostics` on failures102 - A readable raw JSON section (provided by `ModelProbeResults`)1035. For **list** endpoints: per-row mapping inspection from the wire array item (see `Contacts.razor`).1046. For **CRUD** endpoints: detail page with `?id=` deep links; fetch wire JSON after create/update; show `MudProgressLinear` while operations run (see `ContactDetail.razor`).1057. When the SDK exposes **multiple write variants** for the same resource, the sample must be able to invoke each public write method — a variant selector on one CRUD page is sufficient; exercising only one variant (for example income-only) is not.1068. Add seed fixtures when demo data helps field coverage (narrative canon and/or a full-detail probe contact); upsert by a stable natural key when re-running should refresh existing records.1079. Only model wire fields that appear in the official FreeAgent API docs.108109Update [`samples/README.md`](../../samples/README.md) and [`docs/reference/api-coverage.md`](../../docs/reference/api-coverage.md) in the same change.110111## Step 7 — Documentation112113Update the root `README.md`, [`src/FreeAgent.Client/README.md`](../../src/FreeAgent.Client/README.md) (API coverage, usage examples), [`docs/reference/api-coverage.md`](../../docs/reference/api-coverage.md), and any affected plan or entity-map sequencing docs.114115## Step 8 — Validation116117Run from repository root:118119```bash120dotnet build121dotnet test122```123124Highlight any breaking changes applied during retrofit (DateTime → DateOnly, string → enum).125126## References127128- `adr/adr-0010-documented-operations-to-sdk-methods.md`129- `docs/contributing/sample-probe-pages.md`130- `plan/IMPLEMENTING_ENDPOINTS.md`131- `plan/API_TYPE_MAPPING_POLICY.md`132- `plan/API_TO_SDK_ALIGNMENT.md`133- `CONVENTIONS.md`134- `AGENTS.md`