openapi: 3.1.0
info:
  title: VitaKYC API
  version: "1.0.0"
  summary: API publique VitaKYC — KYC · AML · TCR (Tax Compliance & Reporting)
  description: |
    API REST publique de la plateforme VitaKYC. Multi-tenant implicite via le token.
    - Versioning par URL (`/v1/…`)
    - Authentification : `Authorization: Bearer <jwt>` (OIDC) ou `X-API-Key: <key>`
    - Idempotence : header `Idempotency-Key` obligatoire sur tous les POST mutatifs
    - Format d'erreur : RFC 9457 (Problem Details)
    - Pagination cursor-based
    - Webhooks signés HMAC SHA-256
  contact:
    name: VitaKYC Support
    email: support@vitakyc.io
    url: https://docs.vitakyc.e-vitalis.com
  license:
    name: Proprietary
servers:
  - url: https://api.vitakyc.io/v1
    description: Production SaaS (EU Frankfurt)
  - url: https://api.sandbox.vitakyc.io/v1
    description: Sandbox

tags:
  - name: KYC
    description: Dossiers KYC individuels et business
  - name: AML
    description: Screening sanctions / PEP / adverse media et monitoring
  - name: TCR
    description: Tax Compliance & Reporting — FATCA, CRS, DAC6
  - name: Forms
    description: Form Designer — définitions et soumissions
  - name: Webhooks
    description: Abonnements et signatures
  - name: Admin
    description: Gestion tenant, users, licences

security:
  - bearerAuth: []
  - apiKey: []

paths:

  #----------------------------------------------------------------------- KYC
  /kyc/cases:
    post:
      tags: [KYC]
      summary: Créer un dossier KYC
      operationId: createKycCase
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateKycCaseRequest'
      responses:
        '201':
          description: Dossier créé
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KycCase'
        '400': { $ref: '#/components/responses/BadRequest' }
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/TooManyRequests' }

    get:
      tags: [KYC]
      summary: Lister les dossiers KYC
      operationId: listKycCases
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [created, in_progress, auto_approved, manual_review, approved, rejected, expired]
        - name: external_ref
          in: query
          schema: { type: string }
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Liste paginée
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: { $ref: '#/components/schemas/KycCase' }
                  next_cursor: { type: string, nullable: true }

  /kyc/cases/{caseId}:
    parameters:
      - $ref: '#/components/parameters/CaseId'
    get:
      tags: [KYC]
      summary: Consulter un dossier
      operationId: getKycCase
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/KycCase' }
        '404': { $ref: '#/components/responses/NotFound' }

  /kyc/cases/{caseId}/documents:
    parameters:
      - $ref: '#/components/parameters/CaseId'
    post:
      tags: [KYC]
      summary: Uploader un document (recto, verso, selfie, justificatif)
      operationId: uploadDocument
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                kind:
                  type: string
                  enum: [passport, id_card_front, id_card_back, drivers_license, proof_address, trade_license, selfie, rne_extract]
                file:
                  type: string
                  format: binary
              required: [kind, file]
      responses:
        '201':
          description: Document enregistré, pipeline OCR + liveness déclenché
          content:
            application/json:
              schema: { $ref: '#/components/schemas/KycDocument' }

  /kyc/cases/{caseId}/decision:
    parameters:
      - $ref: '#/components/parameters/CaseId'
    post:
      tags: [KYC]
      summary: Forcer une décision manuelle sur le dossier
      operationId: decideKycCase
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                decision: { type: string, enum: [approved, rejected] }
                reason: { type: string }
                agent_id: { type: string, format: uuid }
              required: [decision, reason]
      responses:
        '200':
          description: Décision enregistrée
          content:
            application/json:
              schema: { $ref: '#/components/schemas/KycCase' }

  #----------------------------------------------------------------------- KYB
  /kyb/rne/lookup:
    post:
      tags: [KYC]
      summary: Consulter les web services RNE Tunisie (KYC + UBO)
      operationId: kybRneLookup
      description: |
        Consomme les services RNE via `connector-rne`. Appelle systématiquement WS-KYC,
        et WS-BE uniquement si `declaration_BENEFICIAIRES_EFFECTIFS = Oui`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                rne_identifier:
                  type: string
                  pattern: '^[0-9]{7}[A-Z]$'
                  example: "1616343A"
                services:
                  type: array
                  items: { type: string, enum: [kyc, ubo] }
                  default: [kyc, ubo]
              required: [rne_identifier]
      responses:
        '200':
          description: Données agrégées
          content:
            application/json:
              schema: { $ref: '#/components/schemas/RneLookupResponse' }

  #----------------------------------------------------------------------- AML
  /aml/screen:
    post:
      tags: [AML]
      summary: Screening AML synchrone
      operationId: amlScreen
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AmlScreenRequest' }
      responses:
        '200':
          description: Résultat
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AmlScreenResponse' }

  /aml/subjects/{subjectId}/monitoring:
    parameters:
      - name: subjectId
        in: path
        required: true
        schema: { type: string, format: uuid }
    put:
      tags: [AML]
      summary: Activer / désactiver l'ongoing monitoring
      operationId: toggleAmlMonitoring
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                active: { type: boolean }
                frequency: { type: string, enum: [daily, weekly, on_list_update], default: daily }
              required: [active]
      responses:
        '200':
          description: OK

  /aml/alerts:
    get:
      tags: [AML]
      summary: Lister les alertes AML
      operationId: listAmlAlerts
      parameters:
        - name: status
          in: query
          schema: { type: string, enum: [open, assigned, resolved, false_positive] }
        - name: severity
          in: query
          schema: { type: string, enum: [low, medium, high, critical] }
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Liste paginée

  #----------------------------------------------------------------------- AML — Batch Screening
  /aml/batches:
    post:
      tags: [AML]
      summary: Créer un batch screening AML
      operationId: createAmlBatch
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name: { type: string }
                mode: { type: string, enum: [full, delta, listsdelta, newlist] }
                lists:
                  type: array
                  items:
                    type: string
                    enum: [OFAC, UN, EU, HMT, BCT_LOCAL, SEPBLAC, UAE_CB]
                include_pep: { type: boolean, default: true }
                include_adverse_media: { type: boolean, default: true }
                since: { type: string, format: date-time, nullable: true }
                subjects:
                  type: array
                  items:
                    type: object
                    properties:
                      external_id: { type: string }
                      full_name: { type: string }
                      full_name_ar: { type: string, nullable: true }
                      dob: { type: string, format: date, nullable: true }
                      nationality: { type: string, nullable: true }
                      country_residence: { type: string, nullable: true }
                      type: { type: string, enum: [individual, business], default: individual }
                source:
                  type: object
                  nullable: true
                  description: Alternative à `subjects`, pour interroger le référentiel tenant
                  properties:
                    type: { type: string, enum: [query] }
                    filter: { type: object, additionalProperties: true }
              required: [name, mode, lists]
      responses:
        '202':
          description: Batch accepté, traitement en cours
          content:
            application/json:
              schema:
                type: object
                properties:
                  batch_id: { type: string, format: uuid }
                  status: { type: string, enum: [queued, running, completed, failed, canceled] }
                  subjects_total: { type: integer }
                  estimated_completion: { type: string, format: date-time }

  /aml/batches/csv:
    post:
      tags: [AML]
      summary: Créer un batch screening par upload CSV
      operationId: createAmlBatchCsv
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                name: { type: string }
                mode: { type: string, enum: [full, delta, listsdelta, newlist] }
                lists: { type: string, description: 'CSV (ex: OFAC,UN,EU)' }
                file: { type: string, format: binary }
              required: [name, mode, lists, file]
      responses:
        '202':
          description: Batch accepté
          content:
            application/json:
              schema:
                type: object
                properties:
                  batch_id: { type: string, format: uuid }

  /aml/batches/{batchId}:
    parameters:
      - name: batchId
        in: path
        required: true
        schema: { type: string, format: uuid }
    get:
      tags: [AML]
      summary: Statut d'un batch
      operationId: getAmlBatch
      responses:
        '200':
          description: Détails
          content:
            application/json:
              schema:
                type: object
                properties:
                  batch_id: { type: string, format: uuid }
                  name: { type: string }
                  status: { type: string, enum: [queued, running, completed, failed, canceled] }
                  progress_pct: { type: number }
                  subjects_total: { type: integer }
                  subjects_processed: { type: integer }
                  subjects_with_hits: { type: integer }
                  started_at: { type: string, format: date-time, nullable: true }
                  completed_at: { type: string, format: date-time, nullable: true }
                  report_csv_url: { type: string, format: uri, nullable: true }
                  report_xlsx_url: { type: string, format: uri, nullable: true }
                  report_pdf_url: { type: string, format: uri, nullable: true }

  /aml/batches/{batchId}/hits:
    parameters:
      - name: batchId
        in: path
        required: true
        schema: { type: string, format: uuid }
    get:
      tags: [AML]
      summary: Lister les hits d'un batch
      operationId: listAmlBatchHits
      parameters:
        - name: decision
          in: query
          schema: { type: string, enum: [pending, true_positive, false_positive] }
        - $ref: '#/components/parameters/Cursor'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Liste paginée

  /aml/batches/{batchId}/hits/{hitId}:
    parameters:
      - name: batchId
        in: path
        required: true
        schema: { type: string, format: uuid }
      - name: hitId
        in: path
        required: true
        schema: { type: string, format: uuid }
    patch:
      tags: [AML]
      summary: Revue d'un hit (true / false positive)
      operationId: reviewAmlBatchHit
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                decision: { type: string, enum: [true_positive, false_positive] }
                notes: { type: string }
              required: [decision]
      responses:
        '200':
          description: OK

  /aml/batches/{batchId}/report:
    parameters:
      - name: batchId
        in: path
        required: true
        schema: { type: string, format: uuid }
      - name: format
        in: query
        required: true
        schema: { type: string, enum: [csv, xlsx, pdf] }
    get:
      tags: [AML]
      summary: Télécharger le rapport batch
      operationId: downloadAmlBatchReport
      responses:
        '200':
          description: Fichier
          content:
            text/csv: { schema: { type: string } }
            application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
              schema: { type: string, format: binary }
            application/pdf:
              schema: { type: string, format: binary }

  #----------------------------------------------------------------------- AML — Transaction monitoring (add-on premium)
  /aml/transactions/ingest:
    post:
      tags: [AML]
      summary: Ingestion de transactions (batch ou unitaire)
      operationId: ingestTransactions
      description: |
        Ingestion synchrone (unitaire) ou asynchrone (batch).
        Formats acceptés : JSON VitaKYC canonique, ISO 20022 pacs.008 XML,
        SWIFT MT103 flat, CSV VitaKYC (voir docs AML TxMon).
      parameters:
        - name: format
          in: query
          required: true
          schema:
            type: string
            enum: [json_vitakyc, iso20022_pacs008, swift_mt103, csv_vitakyc]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TransactionBatchJson' }
          application/xml: {}
          text/csv: {}
          text/plain: {}
      responses:
        '202':
          description: Ingestion acceptée, traitement async
          content:
            application/json:
              schema:
                type: object
                properties:
                  batch_id: { type: string, format: uuid }
                  accepted_count: { type: integer }
                  rejected_count: { type: integer }
                  rejected_reasons:
                    type: array
                    items: { type: string }

  /aml/transactions/alerts:
    get:
      tags: [AML]
      summary: Alertes de transaction monitoring
      operationId: listTxMonAlerts
      parameters:
        - name: rule
          in: query
          schema: { type: string }
        - name: account_id
          in: query
          schema: { type: string }
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: Liste paginée

  #----------------------------------------------------------------------- TCR
  /tcr/classifications:
    post:
      tags: [TCR]
      summary: Classification fiscale (FATCA + CRS)
      operationId: tcrClassify
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TcrClassifyRequest' }
      responses:
        '200':
          description: Résultat classification
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TcrClassification' }

  /tcr/forms:
    post:
      tags: [TCR]
      summary: Générer un formulaire W-8BEN / W-8BEN-E / W-9
      operationId: tcrGenerateForm
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                case_id: { type: string, format: uuid }
                type: { type: string, enum: ['W-8BEN', 'W-8BEN-E', 'W-9'] }
                sign_with_esignature: { type: boolean, default: true }
              required: [case_id, type]
      responses:
        '201':
          description: Formulaire généré
          content:
            application/json:
              schema:
                type: object
                properties:
                  form_id: { type: string, format: uuid }
                  pdf_download_url: { type: string, format: uri }
                  esignature_url: { type: string, format: uri, nullable: true }
                  expires_at: { type: string, format: date-time }

  /tcr/declarations:
    post:
      tags: [TCR]
      summary: Générer une déclaration FATCA / CRS
      operationId: tcrCreateDeclaration
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CreateDeclarationRequest' }
      responses:
        '202':
          description: Génération lancée
          content:
            application/json:
              schema:
                type: object
                properties:
                  declaration_id: { type: string, format: uuid }
                  status: { type: string, enum: [generating, generated, submitted, accepted, rejected] }

  /tcr/declarations/{declarationId}/xml:
    parameters:
      - name: declarationId
        in: path
        required: true
        schema: { type: string, format: uuid }
    get:
      tags: [TCR]
      summary: Télécharger le fichier XML FATCA / CRS
      operationId: downloadDeclarationXml
      responses:
        '200':
          description: Fichier XML
          content:
            application/xml:
              schema: { type: string }
            application/gzip:
              schema: { type: string, format: binary }

  /tcr/declarations/{declarationId}/submit-ides:
    parameters:
      - name: declarationId
        in: path
        required: true
        schema: { type: string, format: uuid }
    post:
      tags: [TCR]
      summary: Déposer sur IDES (DGI Tunisie) via proxy VitaKYC
      operationId: submitToIdes
      description: |
        Dépose le fichier FATCA XML v2.0 sur la plateforme IDES de la DGI.
        Nécessite que le tenant ait fourni son certificat ANCE et ses credentials IDES.
      responses:
        '200':
          description: Accusé de dépôt (AD) récupéré
          content:
            application/json:
              schema:
                type: object
                properties:
                  ides_reference: { type: string }
                  deposit_timestamp: { type: string, format: date-time }
                  file_hash_sha256: { type: string }
                  status: { type: string, enum: [accepted, rejected, pending] }

  #----------------------------------------------------------------------- Forms (Form Designer)
  /forms:
    get:
      tags: [Forms]
      summary: Lister les formulaires du tenant
      operationId: listForms
      responses:
        '200':
          description: Liste

  /forms/{formId}/active:
    parameters:
      - name: formId
        in: path
        required: true
        schema: { type: string, format: uuid }
    get:
      tags: [Forms]
      summary: Obtenir la version active d'un formulaire (consommé par le SDK Web)
      operationId: getActiveForm
      responses:
        '200':
          description: Définition JSON du formulaire (schéma + traductions + branding)

  /forms/{formId}/versions/{versionId}/publish:
    parameters:
      - name: formId
        in: path
        required: true
        schema: { type: string, format: uuid }
      - name: versionId
        in: path
        required: true
        schema: { type: string, format: uuid }
    post:
      tags: [Forms]
      summary: Publier une version (activer pour le runtime)
      operationId: publishFormVersion
      responses:
        '200':
          description: Publié

  #----------------------------------------------------------------------- Webhooks
  /webhooks:
    post:
      tags: [Webhooks]
      summary: Créer un abonnement webhook
      operationId: createWebhook
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                url: { type: string, format: uri }
                events:
                  type: array
                  items:
                    type: string
                    enum:
                      - kyc.case.created
                      - kyc.case.decided
                      - aml.alert.created
                      - aml.transaction.alert
                      - tcr.declaration.generated
                      - tcr.declaration.submitted
                      - form.submission.received
                secret_hint: { type: string, description: "Affichage des 4 derniers chars du secret pour rotation" }
              required: [url, events]
      responses:
        '201':
          description: Webhook créé
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhook_id: { type: string, format: uuid }
                  secret: { type: string, description: "Affiché une seule fois" }

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key

  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema: { type: string, format: uuid }
    Cursor:
      name: cursor
      in: query
      schema: { type: string }
    Limit:
      name: limit
      in: query
      schema: { type: integer, default: 50, maximum: 200 }
    CaseId:
      name: caseId
      in: path
      required: true
      schema: { type: string, format: uuid }

  responses:
    BadRequest:
      description: Requête invalide (RFC 9457)
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
    Unauthorized:
      description: Non authentifié
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
    NotFound:
      description: Ressource introuvable
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
    TooManyRequests:
      description: Rate limit dépassé
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }

  schemas:
    Problem:
      type: object
      description: RFC 9457 Problem Details
      properties:
        type: { type: string, format: uri }
        title: { type: string }
        status: { type: integer }
        detail: { type: string }
        instance: { type: string }
        errors:
          type: array
          items:
            type: object
            properties:
              field: { type: string }
              code: { type: string }
              message: { type: string }

    CreateKycCaseRequest:
      type: object
      properties:
        external_ref: { type: string, maxLength: 128 }
        subject_type: { type: string, enum: [individual, business] }
        workflow_code: { type: string, example: 'default-tn-v1' }
        locale: { type: string, example: 'fr-TN' }
        initial_data:
          type: object
          additionalProperties: true
        tags:
          type: array
          items: { type: string }
      required: [subject_type, workflow_code]

    KycCase:
      type: object
      properties:
        case_id: { type: string, format: uuid }
        external_ref: { type: string }
        subject_type: { type: string, enum: [individual, business] }
        status: { type: string, enum: [created, in_progress, auto_approved, manual_review, approved, rejected, expired] }
        risk_score: { type: number, nullable: true }
        decision_reason: { type: string, nullable: true }
        embed_url: { type: string, format: uri, nullable: true }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time, nullable: true }

    KycDocument:
      type: object
      properties:
        document_id: { type: string, format: uuid }
        kind: { type: string }
        ocr_status: { type: string, enum: [pending, done, failed] }
        verification_status: { type: string, enum: [pending, valid, invalid, suspicious] }
        ocr_payload: { type: object, additionalProperties: true }

    RneLookupResponse:
      type: object
      properties:
        kyc:
          type: object
          description: Bloc Fiche Entreprise + Activités + Direction + Pouvoirs (cf. cahier des charges §12.3.1.1)
        ubo:
          type: array
          items: { type: object }
        source: { type: string, enum: [rne_ws, cache] }
        retrieved_at: { type: string, format: date-time }
        cache_ttl_hours: { type: integer }

    AmlScreenRequest:
      type: object
      properties:
        case_id: { type: string, format: uuid, nullable: true }
        subject:
          type: object
          properties:
            full_name: { type: string }
            full_name_transliterations:
              type: array
              items: { type: string }
            dob: { type: string, format: date }
            nationality: { type: string, example: 'TN' }
        lists:
          type: array
          items:
            type: string
            enum: [OFAC, UN, EU, HMT, BCT_LOCAL, SEPBLAC, UAE_CB]
        include_pep: { type: boolean, default: true }
        include_adverse_media: { type: boolean, default: true }
      required: [subject]

    AmlScreenResponse:
      type: object
      properties:
        screening_id: { type: string, format: uuid }
        hits_count: { type: integer }
        decision: { type: string, enum: [auto_clear, manual_review, escalate, block] }
        hits:
          type: array
          items:
            type: object
            properties:
              list_source: { type: string }
              record_id: { type: string }
              match_score: { type: number }
              match_type: { type: string, enum: [sanction, pep, adverse_media, rca] }

    TransactionBatchJson:
      type: object
      properties:
        batch_id: { type: string, format: uuid }
        transactions:
          type: array
          items:
            type: object
            properties:
              tx_id: { type: string }
              timestamp: { type: string, format: date-time }
              account_id: { type: string }
              counterparty:
                type: object
                properties:
                  name: { type: string }
                  iban: { type: string, nullable: true }
                  country: { type: string, example: 'TN' }
                  bic: { type: string, nullable: true }
              amount: { type: number }
              currency: { type: string, example: 'TND' }
              type: { type: string, enum: [transfer, cash_deposit, cash_withdrawal, card_payment, fx, loan_disbursement, loan_repayment] }
              channel: { type: string, enum: [branch, atm, online, mobile, swift, rtgs, correspondent] }
              metadata:
                type: object
                additionalProperties: true
      required: [transactions]

    TcrClassifyRequest:
      type: object
      properties:
        case_id: { type: string, format: uuid }
        include_fatca: { type: boolean, default: true }
        include_crs: { type: boolean, default: true }

    TcrClassification:
      type: object
      properties:
        classification_id: { type: string, format: uuid }
        us_person: { type: boolean }
        fatca_category: { type: string, example: 'FATCA102' }
        holder_type: { type: string, enum: [Individual, Organisation] }
        tax_residences:
          type: array
          items:
            type: object
            properties:
              country: { type: string, example: 'FR' }
              tin: { type: string, nullable: true }
              certified_at: { type: string, format: date-time, nullable: true }
              expires_at: { type: string, format: date-time, nullable: true }
        indicia:
          type: object
          additionalProperties: true

    CreateDeclarationRequest:
      type: object
      properties:
        reporting_fi_giin: { type: string, example: '00Z148.00027.ME.788' }
        reporting_period: { type: string, example: '2025' }
        type: { type: string, enum: [FATCA1, FATCA2, FATCA3, FATCA4, NilReport] }
        filer_category: { type: string, example: 'FATCA601' }
        parent_message_ref_id:
          type: string
          nullable: true
          description: Requis si type ≠ FATCA1
        accounts_filter:
          type: object
          properties:
            reporting_year: { type: integer }
        auto_submit_ides: { type: boolean, default: false }
      required: [reporting_fi_giin, reporting_period, type, filer_category]
