> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mangrovesystems.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Correct a data point value

> Substitutes the value of one data point, addressed by its data point type slug within an event. Use it to replace a wrong reading, or to set a value where none was recorded. The server records the previous value as `from_value`, which is null when no reading existed, and creates the data point on the event if it did not exist yet.

Each call appends to the data point's correction history, so the original reading stays readable.

Setting a value does not recalculate anything downstream. A batch that was already generated keeps the value it was generated with.

**Replays return 200, new corrections return 201.** A call is treated as a replay when the data point's latest correction has both the same `method` and the same value, in which case that existing correction is returned and nothing is written. Values are compared after normalization, so `"10.2"`, `10.2` and a stored `10.20` all match. Note that `method` participates in this check: retrying with a different `method` writes a second correction rather than matching the first.

Requires corrections to be enabled on the account.



## OpenAPI

````yaml PUT /projects/{project_id}/events/{event_id}/data_points/{slug}/value
openapi: 3.1.0
info:
  title: Mangrove - API
  version: 1.1.0
servers:
  - url: https://app.gomangrove.com/api/v1
security:
  - sec0: []
paths:
  /projects/{project_id}/events/{event_id}/data_points/{slug}/value:
    put:
      summary: Correct a data point value
      description: >-
        Substitutes the value of one data point, addressed by its data point
        type slug within an event. Use it to replace a wrong reading, or to set
        a value where none was recorded. The server records the previous value
        as `from_value`, which is null when no reading existed, and creates the
        data point on the event if it did not exist yet.


        Each call appends to the data point's correction history, so the
        original reading stays readable.


        Setting a value does not recalculate anything downstream. A batch that
        was already generated keeps the value it was generated with.


        **Replays return 200, new corrections return 201.** A call is treated as
        a replay when the data point's latest correction has both the same
        `method` and the same value, in which case that existing correction is
        returned and nothing is written. Values are compared after
        normalization, so `"10.2"`, `10.2` and a stored `10.20` all match. Note
        that `method` participates in this check: retrying with a different
        `method` writes a second correction rather than matching the first.


        Requires corrections to be enabled on the account.
      operationId: correct-a-data-point-value
      parameters:
        - name: project_id
          in: path
          schema:
            type: string
          required: true
        - name: event_id
          in: path
          schema:
            type: string
          required: true
          description: >-
            Unique ID of the event in the `evt_XXXX` syntax. For example:
            `evt_DLnYvzbjSujNAvXE`
        - name: slug
          in: path
          schema:
            type: string
          required: true
          description: >-
            Data point type slug on the event's event type. For example:
            `ambient-temperature-c`. A slug the event type does not define
            returns 422.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - value
              properties:
                value:
                  description: >-
                    The corrected value. Number, string or boolean, matching the
                    data point type. Required; a null value returns 400.
                  oneOf:
                    - type: number
                    - type: string
                    - type: boolean
                method:
                  type: string
                  default: manual_entry
                  description: >-
                    How the value was arrived at, recorded on the correction and
                    shown in the audit trail. Free text, and it also decides
                    whether a repeat call is treated as a replay.
                notes:
                  type: string
                  description: Free-text justification stored with the correction.
                expect:
                  type: string
                  enum:
                    - gap
                    - existing
                  description: >-
                    Optional guard on the state you believe the data point is
                    in. Pass `gap` to require that it is currently empty, or
                    `existing` to require that it already has a value. A
                    mismatch returns 422 and writes nothing. Because this
                    endpoint creates the data point when the slug has no value
                    yet, `existing` is the guard that stops a wrong slug or
                    event ID from silently manufacturing data. It only tests
                    empty against non-empty, so it will not detect a value that
                    changed from one number to another.
            examples:
              Correct an existing reading:
                value:
                  value: 12.4
                  expect: existing
                  notes: Sensor drift confirmed against the calibration log.
              Fill a gap:
                value:
                  value: 0
                  method: zero_fill
                  expect: gap
                  notes: Meter offline for maintenance; no flow during the window.
      responses:
        '200':
          description: Replay of the latest correction; nothing was written.
          content:
            application/json:
              examples:
                Result:
                  value:
                    id: sub_9TnpQxL2mKdRvWs4
                    data_point_id: in_kiIuaGIUqRxWUmTY
                    stage: ingestion
                    source: api
                    method: manual_entry
                    origin: substituted
                    from_value: 14.9
                    to_value: 12.4
                    notes: Sensor drift confirmed against the calibration log.
                    rule: null
                    created_by: Aaron Rosenberg
                    created_at: '2026-07-21T14:02:55.000Z'
              schema:
                $ref: '#/components/schemas/DataPointCorrection'
        '201':
          description: Correction applied.
          content:
            application/json:
              examples:
                Result:
                  value:
                    id: sub_9TnpQxL2mKdRvWs4
                    data_point_id: in_kiIuaGIUqRxWUmTY
                    stage: ingestion
                    source: api
                    method: manual_entry
                    origin: substituted
                    from_value: 14.9
                    to_value: 12.4
                    notes: Sensor drift confirmed against the calibration log.
                    rule: null
                    created_by: Aaron Rosenberg
                    created_at: '2026-07-21T14:02:55.000Z'
              schema:
                $ref: '#/components/schemas/DataPointCorrection'
        '400':
          description: '400'
          content:
            application/json:
              examples:
                Result:
                  value:
                    errors:
                      - message: A value is required
        '403':
          description: >-
            Corrections are not enabled on the account, or the token does not
            have Data Collection write permission.
          content:
            application/json:
              examples:
                Corrections not enabled:
                  value:
                    errors:
                      - message: Corrections are not enabled
                Insufficient permission:
                  value:
                    errors:
                      - message: You are not authorized to perform this action
        '422':
          description: '422'
          content:
            application/json:
              examples:
                Unknown slug:
                  value:
                    errors:
                      - message: Unknown data point type 'ambient-temp'
                Expected a gap:
                  value:
                    errors:
                      - message: This data point already has a value
                Expected a value:
                  value:
                    errors:
                      - message: This data point has no value to correct
                Unknown expectation:
                  value:
                    errors:
                      - message: Unknown expectation 'empty' (use 'gap' or 'existing')
      deprecated: false
components:
  schemas:
    DataPointCorrection:
      type: object
      description: One entry in a data point's correction history.
      properties:
        id:
          type: string
          description: Correction friendly ID.
          example: sub_9TnpQxL2mKdRvWs4
        data_point_id:
          type: string
          description: Friendly ID of the corrected data point.
          example: in_kiIuaGIUqRxWUmTY
        stage:
          type: string
          enum:
            - ingestion
            - value_stream
          description: >-
            `ingestion` corrections change the data point's value, which every
            model and report reads. Corrections written through this API are
            always `ingestion`. `value_stream` corrections are overrides scoped
            to a single value stream and leave the shared value untouched; they
            cannot be created here.
        source:
          type: string
          enum:
            - manual
            - api
            - rule
            - transformation
          description: >-
            Where the correction came from. Corrections written through this API
            are `api`.
        method:
          type: string
          description: >-
            How the value was arrived at, as supplied by the caller. Reverts are
            recorded with the reserved method `revert`.
          example: manual_entry
        origin:
          type: string
          enum:
            - substituted
            - imputed
            - reverted
          description: >-
            `substituted` changed an existing reading. `imputed` set a value
            where none was recorded, and is the case the Events table calls
            **Value was missing**. `reverted` restored the previous value.
        from_value:
          description: The value before this entry. Null when no reading existed.
          oneOf:
            - type: number
            - type: string
            - type: boolean
            - type: 'null'
        to_value:
          description: The value after this entry.
          oneOf:
            - type: number
            - type: string
            - type: boolean
            - type: 'null'
        notes:
          type:
            - string
            - 'null'
        rule:
          type:
            - object
            - 'null'
          description: >-
            The data rule that wrote this correction. Null for manual and API
            corrections.
          properties:
            name:
              type: string
            friendly_id:
              type: string
        created_by:
          type:
            - string
            - 'null'
          description: Name of the user the correction is attributed to.
        created_at:
          type: string
          format: date-time
  securitySchemes:
    sec0:
      type: apiKey
      in: header
      name: Authorization
      x-bearer-format: ''

````