# Ed-Fi 1EdTech Source Contract

Read this when you need exact surface boundaries, route families, counts, provenance, or gap-fill behavior.

## Canonical docs

- Customer website: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/customer_website
- Data dictionary: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/data_dictionary
- Architecture: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/architecture
- Surface QC: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/surface_qc
- Integration proof: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/integration
- Live API base: `https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/implementation/api`
- Endpoint catalog: https://platform3-andymontgomery-9773s-projects.vercel.app/ed_fi/1edtech/customer_website/data/endpoint-catalog.json

Official Ed-Fi documentation is upstream source context. The approved platform3 docs are the implementation contract for this surface.

## Surface coverage

The approved implementation exposes the complete Ed-Fi Data Standard v6.1 UDM through one tenant-scoped HTTP API:

- 193 canonical UDM resources.
- 280 descriptor catalogs.
- 473 routed collections.
- 1166 UDM dictionary entries.
- 3991 Ed-Fi standard descriptor seed rows at data-dictionary generation time.

Do not copy those catalogs into an app or report. Treat the numbers as coverage evidence only. When an app needs a value, call the descriptor endpoint and use the returned rows.

## Route families

The public route families are:

- `GET /` - implementation descriptor, route counts, and documentation links. With the hosted canonical base URL, copy-paste curl checks should call `$ED_FI_BASE_URL` without adding a trailing slash to avoid the platform redirect body.
- `GET /ed-fi/{collection}` - list canonical resources or descriptor values.
- `POST /ed-fi/{collection}` - create canonical records or descriptor values.
- `GET /ed-fi/{collection}/{edfi_local_id}` - read by platform-minted local id.
- `PUT /ed-fi/{collection}/{edfi_local_id}` - replace with `If-Match` and `Idempotency-Key`.
- `PATCH /ed-fi/{collection}/{edfi_local_id}` - update with `If-Match` and `Idempotency-Key`.
- `DELETE /ed-fi/{collection}/{edfi_local_id}` - soft-delete with `If-Match` and `Idempotency-Key`.
- `GET|POST /ed-fi/descriptors/{descriptorCatalog}` - governed descriptor catalog routes.
- `GET|POST /ed-fi/drafts` and `POST /ed-fi/drafts/{draft_id}/promote` - pre-canonical write state.
- `GET|POST /ed-fi/imports` and `GET|POST /ed-fi/exports` - bulk job evidence.
- `GET /ed-fi/conformance/evidence` - conformance and implementation evidence.

Use the endpoint catalog to find the exact route for a resource. Do not pluralize or camel-case routes by guessing.

## Attendance teacher marks

Teacher attendance marking is a governed specialization of the generic route family:

- Normal daily marks use append-only `POST /ed-fi/studentSchoolAttendanceEvents`.
- Normal section marks use append-only `POST /ed-fi/studentSectionAttendanceEvents`.
- A mark is confirmed when the response contains both `ack_id` and ETag.
- The root descriptor's `attendanceWritePolicy` publishes policy `edfi.attendance.teacher_mark.v2026-06-22`, `canonicalTeacherMarkWrite: append_only_post`, `correctionWrite: detail_put_patch_delete_with_if_match`, `classroomBatchSize: 32`, `maxClientConcurrency: 8`, and `confirmationTargetSeconds: 30`.
- `PUT`, `PATCH`, and `DELETE` detail routes are correction paths for already acknowledged attendance rows. Do not use mutable detail writes for ordinary between-bells teacher marking.

## List contract

Every list endpoint supports two mutually exclusive paging modes:

- Ed-Fi offset mode: send `limit` and `offset`. Read `page.offset`, `page.nextOffset`, `links.next`, `totalCount`, `page.totalCount`, and the `Total-Count` response header.
- Platform cursor mode: send `limit`, then replay the opaque `page.nextCursor`. Do not decode or construct cursor values.

Never send `cursor` and `offset` together. Mixed or unsupported query parameters return a typed `edfi:invalid_query_parameter` Problem.

Do not count pages locally for collection totals. The surface computes totals after authorization and filters.

## Gap-fill behavior

Every platform-specific behavior traces to an approved ITD:

- GAP-A1: Ed-Fi rows reference platform3 OneRoster sourcedIds. They never mint fallback roster identity.
- GAP-A2: `edfi_local_id` is platform-minted and is not a OneRoster sourcedId or Ed-Fi natural key.
- GAP-A3: DELETE is soft-delete. Hard-delete workarounds are outside the public surface.
- GAP-A4: Ed-Fi descriptors are governed code lists exposed through descriptor endpoints, not copied free-text bags.
- GAP-A5: Draft records are explicit pre-canonical state and carry no platform ack id until promotion.

Related API-axis ITDs cover bulk and per-resource writes, list/detail reads, offset/cursor queries, ETags, idempotency, JWT claims, polling with `modifiedSince`, typed RFC 7807 Problems, tenant routing in JWT, conformance evidence, privacy retention, and complete list endpoints.

## Problem handling

Errors are typed RFC 7807 JSON. Branch on `code`, not free text. Preserve these fields in reports and probes:

- `type`
- `code`
- `status`
- `title`
- `detail`
- `requestId`
- `traceId`
- `fieldErrors`
- `errors`

Common codes include:

- `edfi:invalid_query_parameter`
- `edfi:platform3_roster_required`
- `edfi:descriptor_not_governed`
- `edfi:if_match_required`
- `edfi:etag_mismatch`
- `edfi:idempotency_key_required`
- `edfi:idempotency_conflict`
- `edfi:delete_not_hard_delete`
- `edfi:draft_not_canonical`
- `edfi:privacy_redacted`

If a Problem response is missing those fields, treat that as an implementation issue, not something to repair in client code.

## Provenance rules

For every generated app, report, or probe:

- Link endpoint claims to the customer website or endpoint catalog.
- Link field meaning, nullability, ranges, descriptor sources, and roster overlays to the data dictionary.
- Link platform-specific behavior to the architecture ITD.
- Link live evidence to the actual API request path, tenant mode, response status, and response header/body fields.
