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

# Replace a workflow

> Requires the expected revision via `If-Match: <revision>` (quoted or bare) or body `revision`; 409 on a concurrent update. 409 idv_workflow_archived while archived (restore first). `is_default` and `status` cannot be changed here; use the dedicated endpoints. Sessions already created keep their copied steps/theme.




## OpenAPI

````yaml /api-reference/idv-svc.json put /workflows/{workflowId}
openapi: 3.1.0
info:
  title: Minerva IDV API
  version: 1.0.0-draft
  description: >-
    Customer API for identity verification. Create verification sessions for
    profiles, deliver invites, track capture progress, and read review outcomes.
    For the end-to-end flow, see the [IDV Integration
    Guide](/api-reference/idv-integration-guide). Reviewer-safe responses never
    expose storage keys, checksums, wrapped keys, encryption context, raw OCR,
    or raw model output. Decrypted personal data is available only on `GET
    /sessions/{sessionId}/data`, to an authenticated in-scope principal, with
    fail-closed auditing.
servers:
  - url: https://api.gominerva.com/idv/v1
    description: The production API server for Minerva identity verification
security: []
tags:
  - name: sessions
    description: >-
      Verification sessions and invite delivery (application or dashboard
      authentication).
  - name: capture
    description: End-user capture flow (session or invite credentials).
  - name: review
    description: Review decisions and audited structured-data access.
  - name: workflows
    description: Workflow configuration for verification sessions.
  - name: themes
    description: Branding themes and managed logo assets.
paths:
  /workflows/{workflowId}:
    put:
      tags:
        - workflows
      summary: Replace a workflow
      description: >
        Requires the expected revision via `If-Match: <revision>` (quoted or
        bare) or body `revision`; 409 on a concurrent update. 409
        idv_workflow_archived while archived (restore first). `is_default` and
        `status` cannot be changed here; use the dedicated endpoints. Sessions
        already created keep their copied steps/theme.
      parameters:
        - $ref: '#/components/parameters/WorkflowId'
        - name: If-Match
          in: header
          required: false
          schema:
            type: string
          description: Expected revision (takes precedence over body `revision`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WorkflowUpsertRequest'
      responses:
        '200':
          description: Replaced
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkflowResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
      security:
        - applicationApiKey: []
        - dashboardUserToken: []
components:
  parameters:
    WorkflowId:
      name: workflowId
      in: path
      required: true
      schema:
        type: string
        pattern: ^idvw_[0-9a-f]{24}$
  schemas:
    WorkflowUpsertRequest:
      type: object
      required:
        - name
        - steps
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 500
        profile_kind:
          type: string
          enum:
            - individual
            - organization
            - both
          description: >
            Profile-kind scope (KYB). Absent -> both. A scoped workflow only
            mints sessions for a matching profile (400
            idv_workflow_profile_kind_mismatch otherwise).
        steps:
          type: array
          minItems: 1
          maxItems: 10
          items:
            $ref: '#/components/schemas/WritableFlowStep'
        theme_id:
          description: >
            Must reference a non-archived theme in the caller's scope (400
            idv_theme_not_found / idv_theme_archived otherwise). null/absent =
            use the workspace default theme.
          oneOf:
            - type: string
              pattern: ^idvt_[0-9a-f]{24}$
            - type: 'null'
        status:
          type: string
          description: >-
            Create only: draft (default) or active; archived is rejected. PUT
            rejects it (use /activate and /archive).
          enum:
            - draft
            - active
        is_default:
          type: boolean
          description: Create only (PUT rejects it; use POST .../default).
        retention_days:
          type: integer
          minimum: 30
          maximum: 365
          default: 60
          deprecated: true
          description: >
            DEPRECATED single-horizon alias for pii_retention_days. Supplying
            only this field is understood as asking for all four components at
            this value: the control it belonged to was documented as governing
            both sensitive fields and capture artifacts, so fanning it out
            cannot retain less than the caller intended. This is a FULL REPLACE:
            a component omitted from the request is NOT preserved from the
            stored workflow. It resolves to `retention_days` if that is
            supplied, and to its own default otherwise, so an editor must send
            all four explicitly to avoid resetting a component it did not mean
            to change. Omitting every retention field is not the legacy 60: each
            component takes its own default (biometrics 90, id images 365,
            documents 1825, PII 2555). Values outside 30..365 are rejected.
        assessment_prompt_instructions:
          type: string
          maxLength: 4000
          description: >
            Additional workflow-admin instructions for the review agent. Use for
            stricter or wider flagging behavior before deterministic controls
            exist; empty/omitted means no extra guidance.
        privacy_contact_email:
          oneOf:
            - type: string
              format: email
              maxLength: 254
            - type: string
              maxLength: 0
          description: Required before the workflow can be activated or created as active.
        profile_update_enabled:
          type: boolean
          description: Automatic profile-write opt-in (default false).
        flag_settings:
          $ref: '#/components/schemas/FlagSettings'
        revision:
          type: integer
          description: 'Replace only: the CAS expectation (or use If-Match).'
        supported_features:
          type: array
          maxItems: 16
          uniqueItems: true
          items:
            type: string
            enum:
              - conditional_question_requirements_v1
              - conditional_question_visibility_v1
              - retention_schedules_v1
          description: >
            Request-only editor capability assertions. Required when creating or
            replacing a workflow that contains a listed conditional question
            feature, and when replacing a workflow that already contains one.
            `retention_schedules_v1` asserts the client renders and preserves
            all four per-component retention schedules; it is required on
            REPLACE when the stored schedule is not representable by the
            deprecated `retention_days` alias (i.e. not uniform and inside its
            30..365 clamp) AND the write changes it. Create is never gated. This
            prevents older full-replace editors from silently removing rules
            they do not understand or shortening a schedule they cannot render.
        biometrics_retention_days:
          type: integer
          minimum: 30
          maximum: 1095
          default: 90
          description: >
            Retention of liveness captures AND the cross-session biometric
            templates derived from them, in days. Copied onto sessions at
            create, so later workflow edits affect only future sessions. Capped
            at three years by the most permissive biometric regimes; Quebec's
            one-year ceiling is the tightest.
        id_images_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 365
          description: >
            Retention of identity-document captures (id_front / id_back) in
            days.
        documents_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 1825
          description: |
            Retention of consumer-uploaded supporting documents in days.
        pii_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 2555
          description: >
            Retention of the sensitive fields on a session (subject reference,
            questionnaire answers, capture and invite credentials, OCR fields,
            profile-mismatch details) in days. This is what the deprecated
            retention_days field has always governed.
    WorkflowResponse:
      type: object
      required:
        - data
      properties:
        data:
          $ref: '#/components/schemas/WorkflowObject'
    WritableFlowStep:
      type: object
      additionalProperties: false
      required:
        - step_id
        - type
      properties:
        step_id:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
          description: Unique per session.
        type:
          $ref: '#/components/schemas/WritableStepType'
        required:
          type: boolean
          default: true
          description: false => the consumer may skip the step.
        title:
          type: string
          minLength: 1
          maxLength: 200
          description: Optional display override.
        config:
          $ref: '#/components/schemas/WritableStepConfig'
    FlagSettings:
      type: object
      description: >
        Sparse per-code review overrides. A code ABSENT from the map is ENABLED
        (default-true). Keys are validated against the known configurable
        fraud-flag taxonomy: an unknown key -> 400 idv_flag_code_unknown.
        Deterministic service-enforced policy codes such as id_type_not_allowed
        cannot be disabled and return idv_flag_code_not_configurable.
      additionalProperties:
        type: object
        properties:
          raise_for_review:
            type: boolean
    WorkflowObject:
      type: object
      description: >
        Tenant/workspace-scoped, versioned workflow object. (Distinct from the
        legacy `Workflow` PRESET enum above.) The cycle-2 inline branding block
        is REMOVED; presentation lives on Theme objects referenced by
        `theme_id`.
      required:
        - workflow_id
        - tenant_id
        - workspace_id
        - name
        - profile_kind
        - steps
        - status
        - theme_id
        - is_default
        - retention_days
        - biometrics_retention_days
        - id_images_retention_days
        - documents_retention_days
        - pii_retention_days
        - assessment_prompt_instructions
        - privacy_contact_email
        - created_at
        - updated_at
        - revision
      properties:
        workflow_id:
          type: string
          pattern: ^idvw_[0-9a-f]{24}$
        tenant_id:
          type: string
        workspace_id:
          type: string
        name:
          type: string
          minLength: 1
          maxLength: 120
        description:
          type: string
          maxLength: 500
        profile_kind:
          type: string
          enum:
            - individual
            - organization
            - both
          description: >
            Profile-kind scope (KYB; default both). Session create rejects a
            workflow whose scope does not match the linked profile's kind (400
            idv_workflow_profile_kind_mismatch); the dashboard shows a workflow
            only for the matching profile kind.
        steps:
          type: array
          minItems: 1
          maxItems: 10
          description: EXACTLY the flow-steps step schema (same validator as sessions).
          items:
            $ref: '#/components/schemas/FlowStep'
        status:
          $ref: '#/components/schemas/LifecycleStatus'
        theme_id:
          description: Theme reference or null (= use the workspace default theme).
          oneOf:
            - type: string
              pattern: ^idvt_[0-9a-f]{24}$
            - type: 'null'
        is_default:
          type: boolean
        retention_days:
          type: integer
          minimum: 30
          maximum: 365
          default: 60
          deprecated: true
          description: >
            DEPRECATED alias for pii_retention_days, emitted CLAMPED to 30..365
            so an editor that predates the four-component split reads a value
            inside its own bounds rather than normalizing a longer horizon down
            to its 60-day default and writing that back on save.
        biometrics_retention_days:
          type: integer
          minimum: 30
          maximum: 1095
          default: 90
          description: >
            Retention of liveness captures AND the cross-session biometric
            templates derived from them, in days. Copied onto sessions at
            create, so later workflow edits affect only future sessions. Capped
            at three years by the most permissive biometric regimes; Quebec's
            one-year ceiling is the tightest.
        id_images_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 365
          description: >
            Retention of identity-document captures (id_front / id_back) in
            days.
        documents_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 1825
          description: |
            Retention of consumer-uploaded supporting documents in days.
        pii_retention_days:
          type: integer
          minimum: 30
          maximum: 2555
          default: 2555
          description: >
            Retention of the sensitive fields on a session (subject reference,
            questionnaire answers, capture and invite credentials, OCR fields,
            profile-mismatch details) in days. This is what the deprecated
            retention_days field has always governed.
        assessment_prompt_instructions:
          type: string
          maxLength: 4000
          description: >
            Workflow-admin instructions copied onto future sessions and shown to
            the review agent as policy guidance. The model treats these as
            subordinate to system, schema, privacy, and evidence rules.
        privacy_contact_email:
          oneOf:
            - type: string
              format: email
              maxLength: 254
            - type: string
              maxLength: 0
          description: >
            Consumer-facing privacy/deletion contact embedded in the consent
            notice and copied onto future sessions. Required before a workflow
            can be activated or created as active.
        profile_update_enabled:
          type: boolean
          description: >-
            Automatic profile-write opt-in (default false). Copied onto sessions
            at create.
        flag_settings:
          $ref: '#/components/schemas/FlagSettings'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        revision:
          type: integer
          minimum: 1
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              example: idv_session_not_found
            message:
              type: string
    WritableStepType:
      type: string
      description: Step types accepted by new session/workflow writes.
      enum:
        - liveness
        - id_capture
        - questionnaire
        - document_upload
    WritableStepConfig:
      type: object
      additionalProperties: false
      description: |
        Type-specific configuration accepted on new writes.
      properties:
        accepted_id_types:
          type: array
          maxItems: 20
          description: id_capture only; empty/omitted accepts supported types.
          items:
            $ref: '#/components/schemas/DeclarableIdType'
        custom_id_types:
          type: array
          maxItems: 20
          description: id_capture only; workflow-local document categories.
          items:
            $ref: '#/components/schemas/CustomIdType'
        sides:
          $ref: '#/components/schemas/IdCaptureSides'
        questions:
          type: array
          minItems: 1
          maxItems: 50
          description: questionnaire only.
          items:
            $ref: '#/components/schemas/Question'
        documents:
          type: array
          minItems: 1
          maxItems: 5
          description: >-
            document_upload only; document_id values are unique across the
            workflow.
          items:
            $ref: '#/components/schemas/DocumentSpec'
    FlowStep:
      type: object
      required:
        - step_id
        - type
      properties:
        step_id:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
          description: Unique per session.
        type:
          $ref: '#/components/schemas/StepType'
        required:
          type: boolean
          default: true
          description: false => the consumer may skip the step.
        title:
          type: string
          minLength: 1
          maxLength: 200
          description: Optional display override.
        config:
          $ref: '#/components/schemas/StepConfig'
    LifecycleStatus:
      type: string
      description: >
        Shared management lifecycle (workflows AND themes): draft -> active ->
        archived, archived -> active (restore), draft -> archived. Transitions
        only via the idempotent POST /activate and /archive endpoints, never via
        PUT.
      enum:
        - draft
        - active
        - archived
    DeclarableIdType:
      description: >
        Id types a consumer can declare or configure in accepted_id_types.
        Built-ins are listed explicitly; workflow-local custom ids must be
        defined in the id_capture step's custom_id_types. `unknown` is an
        inference outcome, not declarable. `passport` is the one-sided built-in
        type - declaring it drops id_back when sides=auto.
      anyOf:
        - type: string
          enum:
            - driver_license
            - government_id
            - health_card
            - passport
            - national_id
            - permanent_resident_card
            - residence_permit
            - other
        - type: string
          pattern: ^[a-z0-9_-]{1,64}$
          not:
            enum:
              - driver_license
              - government_id
              - health_card
              - passport
              - national_id
              - permanent_resident_card
              - residence_permit
              - other
              - unknown
    CustomIdType:
      type: object
      required:
        - id_type
        - label
        - sides
      properties:
        id_type:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
          description: >
            Workflow-local id type identifier. Must not match a built-in ID type
            or `unknown`; accepted_id_types can reference it only within the
            same id_capture step.
        label:
          type: string
          minLength: 1
          maxLength: 120
          description: >-
            Human-readable document type label shown to applicants and
            reviewers.
        description:
          type: string
          maxLength: 1000
          description: >
            Optional workflow-admin guidance describing the ID, authenticity
            requirements, and specific details reviewers or the assessment agent
            should inspect for this custom type.
        sides:
          type: string
          enum:
            - one_sided
            - two_sided
          description: Capture side requirement when the custom type is declared.
    IdCaptureSides:
      type: string
      description: >-
        auto adapts to the declared document type; one_sided never demands
        id_back.
      enum:
        - auto
        - two_sided
        - one_sided
      default: auto
    Question:
      type: object
      required:
        - question_id
        - label
        - type
      properties:
        question_id:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
          description: Unique within the step.
        label:
          type: string
          minLength: 1
          maxLength: 500
        type:
          $ref: '#/components/schemas/QuestionType'
        required:
          type: boolean
          default: true
        required_when:
          allOf:
            - $ref: '#/components/schemas/QuestionRequiredWhen'
          description: >-
            Mutually exclusive with required=true; required defaults to false
            when this field is present.
        visible_when:
          allOf:
            - $ref: '#/components/schemas/QuestionCondition'
          description: >
            Shows this otherwise-optional question only when the earlier,
            always-shown and required boolean question has the specified value.
            Mutually exclusive with required=true. If required_when is also
            present, both fields must contain the same condition.
        options:
          type: array
          maxItems: 50
          description: Required for select/multi_select; forbidden otherwise.
          items:
            $ref: '#/components/schemas/QuestionOption'
    DocumentSpec:
      type: object
      required:
        - document_id
        - label
      properties:
        document_id:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
          description: Unique within the full workflow.
        label:
          type: string
          minLength: 1
          maxLength: 200
        description:
          type: string
          maxLength: 1000
        accepted_content_types:
          type: array
          minItems: 1
          maxItems: 4
          uniqueItems: true
          description: Defaults to [application/pdf, image/jpeg, image/png] when omitted.
          items:
            type: string
            enum:
              - application/pdf
              - image/jpeg
              - image/png
              - image/webp
        required:
          type: boolean
          default: true
    StepType:
      type: string
      enum:
        - liveness
        - id_capture
        - questionnaire
        - document_upload
    StepConfig:
      type: object
      description: >-
        Type-specific step config. Only the fields for the step type are
        allowed.
      properties:
        accepted_id_types:
          type: array
          maxItems: 20
          description: >
            id_capture only. Empty/omitted = any supported built-in type plus
            any custom_id_types configured on the same step.
          items:
            $ref: '#/components/schemas/DeclarableIdType'
        custom_id_types:
          type: array
          maxItems: 20
          description: >
            id_capture only. Workflow-local document categories that can be
            referenced from accepted_id_types and declared by the applicant.
          items:
            $ref: '#/components/schemas/CustomIdType'
        sides:
          $ref: '#/components/schemas/IdCaptureSides'
        questions:
          type: array
          minItems: 1
          maxItems: 50
          description: questionnaire only.
          items:
            $ref: '#/components/schemas/Question'
        documents:
          type: array
          minItems: 1
          maxItems: 5
          description: >-
            document_upload only; the full workflow supports at most five
            documents.
          items:
            $ref: '#/components/schemas/DocumentSpec'
    QuestionType:
      type: string
      enum:
        - text
        - textarea
        - select
        - multi_select
        - date
        - country
        - boolean
    QuestionRequiredWhen:
      type: object
      required:
        - question_id
        - equals
      description: >
        Makes an otherwise-optional question required when an earlier,
        always-shown and unconditionally required boolean question has the
        specified value.
      properties:
        question_id:
          type: string
          pattern: ^[a-z0-9_-]{1,64}$
        equals:
          type: boolean
    QuestionCondition:
      allOf:
        - $ref: '#/components/schemas/QuestionRequiredWhen'
      description: >
        Matches an earlier, always-shown and unconditionally required boolean
        question against the specified value.
    QuestionOption:
      type: object
      required:
        - value
        - label
      properties:
        value:
          type: string
          minLength: 1
          maxLength: 128
        label:
          type: string
          minLength: 1
          maxLength: 200
  responses:
    BadRequest:
      description: Validation error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: >-
        Missing or invalid credentials (uniform for token plane, no existence
        oracle)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Resolved dashboard user lacks the required capability or scope
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Session/workflow not found or out of scope (indistinguishable by design)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Domain-state conflict (e.g. concurrent update, illegal transition)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  securitySchemes:
    applicationApiKey:
      type: apiKey
      in: header
      name: Authorization
      description: >-
        `Authorization: Api-Key <application_api_key>` (legacy `X-Api-Key` also
        accepted).
    dashboardUserToken:
      type: apiKey
      in: header
      name: x-user-token
      description: >
        Dashboard session token for Minerva dashboard users. Management routes
        accept it alongside an application API key; any in-scope workspace user
        (member or above) can read sessions and record review decisions, while
        workflow and theme writes need a management-capable role. Send it with
        the `x-tenant-id` and `x-workspace-id` headers; a header/access mismatch
        is refused with 403, and when dashboard authentication is disabled (the
        default) any request carrying this header gets a uniform 401.

````