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

# Create or update records

> Writes records to the catalog. Send either a JSON list of records (`Content-Type: application/json`) or a CSV file (`multipart/form-data`, field `file`, headers as in the CSV template).

Writes are **all-or-nothing**: if any record or row fails validation, nothing in the request is written and `errors` lists every problem.

**Modes**
- `upsert` (default): records in the request are inserted, or merged into the existing record with the same id. Records not in the request are left alone.
- `reconcile`: the request is treated as your **complete** catalog. Records in it are inserted or updated, and every active record not in it is deactivated (never hard-deleted, so it can be restored by sending it again). If a reconcile would deactivate more than half of a non-empty catalog, it is rejected with a `shrink_guard` error unless you pass `confirm_shrink=true`. An empty list or a CSV with no data rows is always rejected in this mode.

Use `dry_run=true` to validate and get the counts without writing anything.

`overwrite=true` (CSV only) hard-deletes the whole catalog and replaces it with the file, in one transaction. It cannot be combined with `mode=reconcile`; prefer `reconcile`, which can be undone.



## OpenAPI

````yaml post /admin/datasets/v1/
openapi: 3.1.0
info:
  title: Eka Care Datasets API
  description: >-
    Manage your workspace's formulary catalogs (medications, lab tests, symptoms
    and diagnoses): upload them as JSON or CSV, keep them in sync, read them
    back, and switch on partner search in the Eka Medical Database. Every
    request acts only on the workspace your access token belongs to.
  version: 1.0.0
  contact:
    name: Eka Care Support
    url: https://eka.care/
    email: support@eka.care
servers:
  - url: https://api.eka.care
    description: Production
  - url: https://api.dev.eka.care
    description: Stage/Sandbox
security:
  - BearerAuth: []
tags:
  - name: datasets
paths:
  /admin/datasets/v1/:
    post:
      tags:
        - datasets
      summary: Create or update records
      description: >-
        Writes records to the catalog. Send either a JSON list of records
        (`Content-Type: application/json`) or a CSV file (`multipart/form-data`,
        field `file`, headers as in the CSV template).


        Writes are **all-or-nothing**: if any record or row fails validation,
        nothing in the request is written and `errors` lists every problem.


        **Modes**

        - `upsert` (default): records in the request are inserted, or merged
        into the existing record with the same id. Records not in the request
        are left alone.

        - `reconcile`: the request is treated as your **complete** catalog.
        Records in it are inserted or updated, and every active record not in it
        is deactivated (never hard-deleted, so it can be restored by sending it
        again). If a reconcile would deactivate more than half of a non-empty
        catalog, it is rejected with a `shrink_guard` error unless you pass
        `confirm_shrink=true`. An empty list or a CSV with no data rows is
        always rejected in this mode.


        Use `dry_run=true` to validate and get the counts without writing
        anything.


        `overwrite=true` (CSV only) hard-deletes the whole catalog and replaces
        it with the file, in one transaction. It cannot be combined with
        `mode=reconcile`; prefer `reconcile`, which can be undone.
      operationId: writeDatasetRecords
      parameters:
        - $ref: '#/components/parameters/Type'
        - name: mode
          in: query
          required: false
          description: >-
            `upsert` leaves records not in the request alone; `reconcile`
            deactivates them.
          schema:
            type: string
            enum:
              - upsert
              - reconcile
            default: upsert
        - name: dry_run
          in: query
          required: false
          description: Validate and count without writing.
          schema:
            type: boolean
            default: false
        - name: confirm_shrink
          in: query
          required: false
          description: Allow a reconcile that deactivates more than half of the catalog.
          schema:
            type: boolean
            default: false
        - name: overwrite
          in: query
          required: false
          description: >-
            CSV only. Replace the whole catalog with the file. Not allowed with
            `mode=reconcile`.
          schema:
            type: boolean
            default: false
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
              minItems: 1
              description: Records of the type named in `type`.
              items:
                oneOf:
                  - $ref: '#/components/schemas/Medication'
                  - $ref: '#/components/schemas/LabTest'
                  - $ref: '#/components/schemas/Symptom'
                  - $ref: '#/components/schemas/Diagnosis'
            example:
              - medication_id: DRUG1001
                name: Dolo 650
                strength: 650mg
                generic_name: Paracetamol
                form_name: Tablet
                manufacturer: Micro Labs Ltd
              - medication_id: DRUG1002
                name: Augmentin 625 Duo
                generic_list:
                  - Amoxicillin
                  - Clavulanic Acid
                form_name: Tablet
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: >-
                    CSV with one header row. Column names match the record
                    fields; multi-value cells are pipe-separated
                    (`Dolo|Paracetamol 650`), except `generic_list` and
                    `generic_list_ids`, which use `+`.
      responses:
        '200':
          description: Written (or, with `dry_run=true`, validated and counted).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WriteResponse'
              example:
                success: true
                message: 2 medication upserted
                data:
                  upserted: 2
                  inserted: 1
                  updated: 1
                  reactivated: 0
                  deactivated: 0
                  dry_run: false
        '400':
          description: >-
            Validation failed, the shrink guard stopped a reconcile, or the
            request was malformed. Nothing was written.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                validation:
                  summary: A record failed validation
                  value:
                    success: false
                    message: validation failed
                    errors:
                      - index: 1
                        field: name
                        msg: required
                        value: null
                shrinkGuard:
                  summary: Reconcile would deactivate most of the catalog
                  value:
                    success: false
                    message: >-
                      reconcile would deactivate 800 of 1000 active rows; pass
                      confirm_shrink=true to proceed
                    errors:
                      - code: shrink_guard
                        active_before: 1000
                        would_deactivate: 800
        '401':
          $ref: '#/components/responses/Unauthorized'
        '413':
          $ref: '#/components/responses/PayloadTooLarge'
components:
  parameters:
    Type:
      name: type
      in: query
      required: true
      description: Which catalog to act on.
      schema:
        type: string
        enum:
          - medication
          - lab_test
          - symptom
          - diagnosis
  schemas:
    Medication:
      type: object
      title: Medication
      required:
        - medication_id
        - name
      properties:
        medication_id:
          type: string
          maxLength: 200
          description: Your id for the drug.
        name:
          type: string
          maxLength: 200
        aliases:
          type: array
          items:
            type: string
            maxLength: 200
          description: Alternate names and short forms, used by search.
        display_name:
          type: string
          maxLength: 200
          description: Shown to end users. Defaults to `name`.
        strength:
          type: string
          maxLength: 32
        generic_name:
          type: string
          maxLength: 300
        generic_id:
          type: string
          maxLength: 64
        generic_list:
          type: array
          items:
            type: string
            maxLength: 100
          description: All generic (salt) components.
        generic_list_ids:
          type: array
          items:
            type: string
            maxLength: 64
        form_name:
          type: string
          maxLength: 64
          description: >-
            Dosage form. Matched case-insensitively against the [accepted drug
            forms](/api-reference/datasets/forms); a match links the drug to
            Eka's form, and any other value is stored as text without that link.
        sku:
          type: string
          maxLength: 64
        schedule_code:
          type: string
          maxLength: 32
        custom_type:
          type: string
          maxLength: 64
        therapy_class:
          type: string
          maxLength: 128
        therapy_class_id:
          type: string
          maxLength: 64
        action_class:
          type: string
          maxLength: 128
        action_class_id:
          type: string
          maxLength: 64
        manufacturer:
          type: string
          maxLength: 200
        otc:
          type: boolean
        is_active:
          type: boolean
          description: Defaults to true on write.
        updated_at:
          type: string
          format: date-time
          readOnly: true
    LabTest:
      type: object
      title: LabTest
      required:
        - lab_test_id
        - name
        - kind
        - result_type
      description: >-
        `specimen` is required when `kind` is `laboratory`, `unit` when
        `result_type` is `numerical`, and `panel_members` when `kind` is
        `panel`.
      properties:
        lab_test_id:
          type: string
          maxLength: 200
          description: Your id for the test.
        name:
          type: string
          maxLength: 200
        display_name:
          type: string
          maxLength: 200
          description: Shown to end users. Defaults to `name`.
        aliases:
          type: array
          items:
            type: string
            maxLength: 200
        loinc:
          type: string
          maxLength: 32
          description: LOINC code. Not checked against the LOINC vocabulary.
        kind:
          type: string
          enum:
            - imaging
            - laboratory
            - functional
            - special_test
            - package
            - panel
        result_type:
          type: string
          enum:
            - numerical
            - ordinal
            - string
            - na
        discipline:
          type: array
          items:
            type: string
            maxLength: 100
          description: For example biochemistry, hematology, micro, molecular, cardiology.
        specimen:
          type: string
          maxLength: 100
        unit:
          type: string
          maxLength: 32
        unit_id:
          type: string
          maxLength: 64
        panel_members:
          type: array
          items:
            type: string
            maxLength: 200
          description: Names of the member tests.
        panel_member_ids:
          type: array
          items:
            type: string
            maxLength: 200
        method:
          type: string
          maxLength: 100
          description: For example ELISA, RAPID_ICT, CHEMILUMINESCENCE (CLIA).
        body_part:
          type: string
          maxLength: 100
          description: Imaging only.
        laterality:
          type: string
          maxLength: 32
          description: Imaging only.
        view:
          type: string
          maxLength: 64
          description: Imaging only.
        is_active:
          type: boolean
          description: Defaults to true on write.
        updated_at:
          type: string
          format: date-time
          readOnly: true
    Symptom:
      type: object
      title: Symptom
      required:
        - symptom_id
        - name
      properties:
        symptom_id:
          type: string
          maxLength: 200
          description: Your id for the symptom.
        name:
          type: string
          maxLength: 200
        display_name:
          type: string
          maxLength: 200
          description: Shown to end users. Defaults to `name`.
        aliases:
          type: array
          items:
            type: string
            maxLength: 200
        snomed_id:
          type: string
          maxLength: 32
          description: SNOMED CT concept id. Not checked against the vocabulary.
        icd10:
          type: string
          maxLength: 32
        icd10_term:
          type: string
          maxLength: 255
        gender:
          type:
            - string
            - 'null'
          enum:
            - M
            - F
            - null
          description: Leave empty when the symptom applies to everyone.
        is_active:
          type: boolean
          description: Defaults to true on write.
        updated_at:
          type: string
          format: date-time
          readOnly: true
    Diagnosis:
      type: object
      title: Diagnosis
      required:
        - diagnosis_id
        - name
      properties:
        diagnosis_id:
          type: string
          maxLength: 200
          description: Your id for the diagnosis.
        name:
          type: string
          maxLength: 200
        display_name:
          type: string
          maxLength: 200
          description: Shown to end users. Defaults to `name`.
        aliases:
          type: array
          items:
            type: string
            maxLength: 200
        snomed_id:
          type: string
          maxLength: 32
          description: SNOMED CT concept id. Not checked against the vocabulary.
        icd10:
          type: string
          maxLength: 32
        icd10_term:
          type: string
          maxLength: 255
        gender:
          type:
            - string
            - 'null'
          enum:
            - M
            - F
            - null
          description: Leave empty when the diagnosis applies to everyone.
        is_active:
          type: boolean
          description: Defaults to true on write.
        updated_at:
          type: string
          format: date-time
          readOnly: true
    WriteResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessEnvelope'
        - type: object
          properties:
            data:
              type: object
              properties:
                upserted:
                  type: integer
                  description: inserted + updated + reactivated.
                inserted:
                  type: integer
                updated:
                  type: integer
                reactivated:
                  type: integer
                  description: Previously inactive records made active again.
                deactivated:
                  type: integer
                  description: Records deactivated by a reconcile. Always 0 in upsert mode.
                dry_run:
                  type: boolean
                batch_id:
                  type: integer
                  description: CSV uploads only. Matches `batch_id` in the batches list.
    ErrorResponse:
      type: object
      required:
        - success
        - message
      properties:
        success:
          type: boolean
          const: false
        message:
          type: string
        errors:
          type: array
          description: >-
            Present when validation failed or the shrink guard stopped a
            reconcile.
          items:
            oneOf:
              - $ref: '#/components/schemas/FieldError'
              - $ref: '#/components/schemas/ShrinkGuardError'
    SuccessEnvelope:
      type: object
      required:
        - success
        - message
      properties:
        success:
          type: boolean
          const: true
        message:
          type: string
    FieldError:
      type: object
      properties:
        index:
          type:
            - integer
            - 'null'
          description: >-
            For a JSON body, the 0-based position of the failing record in the
            list. For a CSV, the 1-based data row (the header row is not
            counted). `null` for a file-level error.
        field:
          type:
            - string
            - 'null'
        msg:
          type: string
        value:
          description: The rejected value.
    ShrinkGuardError:
      type: object
      properties:
        code:
          type: string
          const: shrink_guard
        active_before:
          type: integer
        would_deactivate:
          type: integer
  responses:
    Unauthorized:
      description: The access token is missing, invalid or expired.
    PayloadTooLarge:
      description: >-
        The request body is larger than 10 MB. Split the upload into several
        upsert requests.
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Access token for your workspace.

````