---
title: "Compute a period's DMR values from the plant's own monitoring rows"
method: POST
path: "/dmr/fill"
---

# Compute a period's DMR values from the plant's own monitoring rows

`POST /dmr/fill`

## Request

- Base URL: `https://passage-data.com/api/v1`
- URL: `https://passage-data.com/api/v1/dmr/fill`
- Auth: one of:
  - none
  - HTTP bearer
  - API key in header `x-api-key`

The numbers a US NPDES permit's Discharge Monitoring Report asks for in one period, computed from the plant's own raw results (daily samples, flows): for each value due on the period's forms (EPA's national limits file) its statistic as EPA defines it (monthly average, daily maximum, weekly average over EPA's Sunday-to-Saturday weeks, geometric mean, loadings in lb/d from concentration x flow x 8.34, percent removal), the rows it was computed from, and EPA's violation rule's verdict against the limit. A value the rows cannot give is refused with its code (fill.no_column, fill.unit, fill.ambiguous, dmr.nd_rule_missing ...): a number the rows do not hold is never supplied. Send `rows` as JSON (date, parameter, value, unit, point) or `table` as the file's text (a laboratory's long export, or a sheet of days with one column per parameter); include the previous month's last days when a weekly average is due. A result below detection enters an average by `nd_rule` (zero, half, dl, dl_lt), else by the state's written rule. `netdmr: true` adds the NetDMR "Import DMRs" file as text (not yet validated by NetDMR's own import check). The rows reach our server to be computed and are not kept: only how many rows were sent and values filled is counted.

## Request body

- object
  - `permit` string, required: The NPDES permit number, e.g. PA0228061.
  - `period_end` string, required: The reporting period: its month (2026-09) or its last day (2026-09-30).
  - `rows` object[]: The plant's results, one a row (send rows or table).
    - `date` string, required: The sample's day: 2026-09-01 or 9/1/2026.
    - `parameter` string, required: As the plant's log names it: TSS, CBOD5, Ammonia-N, Flow, pH, E. coli, Copper ...
    - `value` union, required: The result: 12, or "<0.5" below detection, or "ND" with a detection_limit.
      - number
      - string
    - `unit` string: mg/L, ug/L, MGD, SU, #/100mL ...
    - `point` string: Where it was sampled, as the plant names it: Influent, Effluent, Outfall 002 ...
    - `outfall` string: Optional: the outfall the sample belongs to, read with the point.
    - `qualifier` string: Optional: <, >, or ND.
    - `detection_limit` union: Optional: the detection or reporting limit of an ND result.
      - number
      - string
  - `table` union: The plant's file as text (CSV, TSV or semicolons; at most 2000000 characters) or as lines of cells (send rows or table).
    - string
    - array[]
      - unknown[]
        - unknown
  - `nd_rule` 'zero' | 'half' | 'dl' | 'dl_lt': How a result below detection enters an average: as zero, half the limit, the limit (dl), or the limit reported as less-than (dl_lt). Default: the state's written rule, else none (such a statistic is refused).
  - `netdmr` boolean: Also return the NetDMR "Import DMRs" file (CSV text) for the values filled.

## Response `200`

Each value due, computed with the rows it came from and its verdict, or refused with its code

- object

## Other responses

- `400`: permit.missing, permit.malformed, period.missing, period.malformed, rows.missing, rows.malformed, rows.too_many, table.malformed, table.too_many, nd_rule.malformed, body.malformed
- `404`: permit.not_held
- `413`: table.too_large, body.too_large

---

[API](https://skmtc.dev/passage-data/apis/passage-data-cited-environmental-limits.md) · [All operations](https://skmtc.dev/passage-data/apis/passage-data-cited-environmental-limits/llms.txt) · [OpenAPI document](https://skmtc.dev/passage-data/apis/passage-data-cited-environmental-limits/revisions/ba066708bf53?raw)
