{
  "openapi": "3.1.0",
  "info": {
    "title": "MasteryHive Reconciliation \u2014 Ingestion (Partner entry)",
    "version": "0.1.0",
    "description": "Partner money/asset ingestion. root_path /v1. Local servers only."
  },
  "servers": [
    {
      "url": "http://localhost:8000/v1",
      "description": "Local mesh placeholder \u2014 replace host; keep /v1 prefix. Cloud bases require owner decision."
    }
  ],
  "paths": {
    "/": {
      "get": {
        "summary": "Home",
        "operationId": "home__get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "Health",
        "operationId": "health_health_get",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          }
        }
      }
    },
    "/ingestion/background": {
      "post": {
        "tags": [
          "Ingestion"
        ],
        "summary": "Parse GL + Bank files, store to BigQuery, then trigger reconciliation-engine",
        "operationId": "ingest_ingestion_background_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IngestionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/ingestion/asset": {
      "post": {
        "tags": [
          "Ingestion"
        ],
        "summary": "Parse portfolio holdings + custodian report, store to BigQuery, then trigger asset reconciliation",
        "description": "Fund Management asset reconciliation \u2014 internal holdings vs custodian report.\n\nA separate endpoint per reconciliation type so the payload states what it is\nreconciling instead of the caller encoding it in customer_type/reconciliation_type\nand nulling every field another flow owns: here the portfolios, the custodian and\nthe tenant's own asset classes are all required, and there is no template or\nsettings to send. Everything after validation is the shared pipeline.",
        "operationId": "ingest_asset_ingestion_asset_post",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssetIngestionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "202": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "AssetClassInput": {
        "properties": {
          "id": {
            "type": "string",
            "title": "Id",
            "description": "Software-side asset class id"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Display name, e.g. 'Federal Government Bonds'"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "title": "AssetClassInput",
        "description": "One asset class, as the software side defines it.\n\nThe list is created there and travels with the upload, so the vocabulary a fund's\nholdings are classified under is the customer's own \u2014 nothing is seeded on our side.\n`name` is the text the file's class labels (a per-row class column, or the section\nheaders on a hierarchical spool) are matched against; `id` is what every matching\nrow is stamped with and what comes back on each match/break as `asset_class_code`."
      },
      "AssetIngestionRequest": {
        "properties": {
          "partner_id": {
            "type": "string",
            "title": "Partner Id",
            "description": "Optional here, unlike every money flow: the custodian owns a holdings book, so `custodian_id` is used as the scope key when no institution is named. Send it only when a real institution sits above the custodian \u2014 it is then bound to that custodian for good.",
            "default": ""
          },
          "partner_name": {
            "type": "string",
            "title": "Partner Name",
            "description": "Display name of the institution above the custodian. Defaults to `custodian_name` when no institution is named.",
            "default": ""
          },
          "session_id": {
            "type": "string",
            "title": "Session Id",
            "description": "Unique session identifier"
          },
          "tenant_id": {
            "type": "string",
            "title": "Tenant Id",
            "description": "Unique tenant identifier"
          },
          "bank_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bank Name",
            "description": "Bank name (alias for partner_name)"
          },
          "customer_type": {
            "$ref": "#/components/schemas/ReconciliationCustomerTypeEnum",
            "description": "Always 'fund_manager' on this endpoint.",
            "default": "fund_manager"
          },
          "card_scheme": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CardSchemeEnum"
              },
              {
                "type": "null"
              }
            ],
            "description": "Card scheme (e.g. 'visa', 'mastercard', 'verve')"
          },
          "bank_service": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ServiceType"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional bank service"
          },
          "is_switch": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Switch",
            "description": "Set to true to indicate Interswitch."
          },
          "switch_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Switch Type",
            "description": "Switch type identifier."
          },
          "is_scheduled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Scheduled",
            "description": "Indicates if this reconciliation was triggered by a schedule."
          },
          "branch_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Branch Id",
            "description": "Unique branch identifier"
          },
          "branch_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Branch Name",
            "description": "Name of the bank branch"
          },
          "existing_session_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Existing Session Id",
            "description": "Existing Session Id"
          },
          "last_processed_step": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Processed Step",
            "description": "Last processed step"
          },
          "period_start_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period Start Date",
            "description": "Not used by asset reconciliation \u2014 holdings are a snapshot, so nothing is period-filtered. Omit it."
          },
          "period_end_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period End Date",
            "description": "Not used by asset reconciliation \u2014 holdings are a snapshot, so nothing is period-filtered. Omit it."
          },
          "on_existing_action": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ReconciliationMode"
              },
              {
                "type": "null"
              }
            ],
            "default": "overwrite"
          },
          "reconciliation_flow": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reconciliation Flow",
            "description": "NIP reconciliation flow direction: 'inward' | 'outward'. Only meaningful when customer_type is commercial_bank and the template's service is ServiceType.NIP."
          },
          "is_settlement": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Settlement",
            "description": "Deprecated -- ignored. NIP reconciliation is now classified by customer_type + the template's service (ServiceType.NIP), not by this flag. Accepted here only so older callers that still send it aren't rejected; it has no effect on dispatch."
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings",
            "description": "Settings overrides (partial)"
          },
          "template": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Template",
            "description": "Template configuration (full or partial)"
          },
          "ingress_task_id": {
            "type": "string",
            "title": "Ingress Task Id",
            "description": "Ingress task identifier"
          },
          "records_create_task_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Records Create Task Id",
            "description": "Records create task identifier"
          },
          "gl_reversal_task_id": {
            "type": "string",
            "title": "Gl Reversal Task Id",
            "description": "GL reversal task identifier"
          },
          "reconciliation_task_id": {
            "type": "string",
            "title": "Reconciliation Task Id",
            "description": "Reconciliation task identifier"
          },
          "matched_records_task_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Matched Records Task Id",
            "description": "Matched records task identifier"
          },
          "summary_task_id": {
            "type": "string",
            "title": "Summary Task Id",
            "description": "Summary task identifier"
          },
          "exclude_debits_from_rate": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exclude Debits From Rate",
            "description": "Exclude debit-only and fee transactions from match rate denominator",
            "default": true
          },
          "exception_analysis_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exception Analysis Enabled",
            "description": "Run exception clustering on unmatched records after reconciliation completes",
            "default": true
          },
          "gl_file_url": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gl File Url",
            "description": "Derived from `portfolios` \u2014 do not send it."
          },
          "bank_file_url": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Bank File Url",
            "description": "List of URLs or paths to Bank Statement files"
          },
          "mappings": {
            "items": {
              "$ref": "#/components/schemas/ColumnMapping"
            },
            "type": "array",
            "title": "Mappings",
            "description": "List of column mappings"
          },
          "others": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OthersMapping"
              },
              {
                "type": "null"
              }
            ],
            "description": "Other mappings for GL and Statement"
          },
          "event_dates": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/EventDate"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Event Dates",
            "description": "Calendar event/holiday date ranges for settlement date calculation"
          },
          "portfolios": {
            "items": {
              "$ref": "#/components/schemas/PortfolioInput"
            },
            "type": "array",
            "title": "Portfolios",
            "description": "The internal portfolios this session reconciles, as one nested list of portfolio objects \u2014 [[{id, name, code, url}, \u2026]], one object per portfolio. Every row of each file is stamped with its portfolio id and name, so several portfolios reconcile against the single custodian report in bank_file_url. A flat [{\u2026}] list is accepted too, as is the legacy { portfolio: [file_urls] } mapping (which carries no ids)."
          },
          "custodian_id": {
            "type": "string",
            "title": "Custodian Id",
            "description": "Id of the custodian whose report is in bank_file_url. Holdings must be attributable to one: the tables hold every custodian's book for a partner, so an unscoped run would reconcile a portfolio against the union of them. It is also the scope key when no partner_id is sent. Send an owning institution in partner_id and that pairing is bound on first use and enforced on every later upload."
          },
          "custodian_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Custodian Name",
            "description": "Custodian display name (e.g. First Nominees Nigeria Limited). Display only \u2014 never used for matching or scoping."
          },
          "asset_classes": {
            "items": {
              "$ref": "#/components/schemas/AssetClassInput"
            },
            "type": "array",
            "title": "Asset Classes",
            "description": "The asset classes this fund reconciles under, as created on the software side \u2014 [{id, name}]. These ids are the identity: the file's own class labels are resolved onto this list and every row is stamped with the matching id. The spelling need not match \u2014 'BANK PLACEMENTS' reaches a 'Fixed Deposits' class, 'NTB' reaches a treasury-bill one \u2014 and each class's instrument family and ISIN-searchability are read off what it actually is. Send [] and rows carry no class id."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "session_id",
          "tenant_id",
          "ingress_task_id",
          "gl_reversal_task_id",
          "reconciliation_task_id",
          "summary_task_id",
          "bank_file_url",
          "mappings",
          "portfolios",
          "custodian_id",
          "asset_classes"
        ],
        "title": "AssetIngestionRequest",
        "description": "Fund Management asset reconciliation \u2014 internal holdings vs custodian report.\n\nIts own endpoint (``POST /ingestion/asset``) so the payload states the flow instead\nof the caller encoding it in ``customer_type``/``reconciliation_type`` and nulling\nevery banking field: what asset reconciliation needs is REQUIRED here (the\nportfolios, the custodian, the asset classes) and what it has no concept of is\nsimply not asked for \u2014 there is no template and no settings for a holdings run,\nsince there are no fee rules, no service and no reversal window to configure.\n\nOnly the contract at the door differs. Dispatch, the period lock, the fan-out and\nthe ETL are the same ones the generic endpoint uses, so the two can never drift.",
        "example": {
          "asset_classes": [
            {
              "id": "9f1c1e0a-1d2b-4c3d-8e4f-5a6b7c8d9e01",
              "name": "Federal Government Bonds"
            },
            {
              "id": "9f1c1e0a-1d2b-4c3d-8e4f-5a6b7c8d9e02",
              "name": "Corporate Bonds"
            },
            {
              "id": "9f1c1e0a-1d2b-4c3d-8e4f-5a6b7c8d9e03",
              "name": "Fixed Deposits"
            },
            {
              "id": "9f1c1e0a-1d2b-4c3d-8e4f-5a6b7c8d9e04",
              "name": "Equities"
            }
          ],
          "bank_file_url": [
            "https://storage.googleapis.com/.../custodian/First-Nom-Custody-Report.xlsx"
          ],
          "custodian_id": "cd1d724f-0f4b-463e-8067-1e095a9efd7f",
          "custodian_name": "First Nominee",
          "customer_type": "fund_manager",
          "gl_reversal_task_id": "1eaae3e3-5512-4baf-a5e1-3316178ea319",
          "ingress_task_id": "a7efaecd-6bf2-4f97-a022-b1108683dbaz",
          "is_scheduled": false,
          "mappings": [
            {
              "gl_title": "",
              "statement_title": "Participant name",
              "system": "Portfolio"
            },
            {
              "gl_title": "",
              "statement_title": "Instrument",
              "system": "Isin"
            },
            {
              "gl_title": "Asset Class Security",
              "statement_title": "Instrument Name",
              "system": "Instrument Name"
            },
            {
              "gl_title": "MaturityDate",
              "statement_title": "Maturity date",
              "system": "Maturity Date"
            },
            {
              "gl_title": "Holding",
              "statement_title": "Available amount",
              "system": "Face Value"
            }
          ],
          "others": {
            "gl": [],
            "statement": [
              "S No"
            ]
          },
          "portfolios": [
            [
              {
                "code": "PBN",
                "id": "7f3a9c21-6d84-4b52-a1e7-3c9f8d6204ab",
                "name": "Private Banking Notes",
                "url": "https://storage.googleapis.com/.../portfolio/PBN.xlsx"
              },
              {
                "code": "LMN",
                "id": "c5e81247-9b36-4fa1-8d72-6a0e3f9152cd",
                "name": "Liquidity MGT Notes",
                "url": "https://storage.googleapis.com/.../portfolio/LMN.xlsx"
              }
            ]
          ],
          "reconciliation_task_id": "e50b5f45-59cb-4705-94b8-55fef764b14v",
          "session_id": "21885881-988e-439e-ae4c-d43d4e1ca0c2",
          "summary_task_id": "5c5ae205-8df6-4668-b251-373d59c79e59",
          "tenant_id": "abbey"
        }
      },
      "CardSchemeEnum": {
        "type": "string",
        "enum": [
          "mastercard",
          "visa",
          "verve"
        ],
        "title": "CardSchemeEnum"
      },
      "ColumnMapping": {
        "properties": {
          "system": {
            "type": "string",
            "title": "System",
            "description": "System field name"
          },
          "gl_title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gl Title",
            "description": "General Ledger column title"
          },
          "statement_title": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Statement Title",
            "description": "Bank Statement column title"
          },
          "secondary_mappings": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/SecondaryMapping"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Secondary Mappings",
            "description": "Secondary mappings for GL and Statement"
          }
        },
        "type": "object",
        "required": [
          "system"
        ],
        "title": "ColumnMapping"
      },
      "EventDate": {
        "properties": {
          "start_date": {
            "type": "string",
            "format": "date",
            "title": "Start Date"
          },
          "end_date": {
            "type": "string",
            "format": "date",
            "title": "End Date"
          }
        },
        "type": "object",
        "required": [
          "start_date",
          "end_date"
        ],
        "title": "EventDate"
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "IngestionRequest": {
        "properties": {
          "partner_id": {
            "type": "string",
            "title": "Partner Id",
            "description": "Unique identifier for the partner or client"
          },
          "partner_name": {
            "type": "string",
            "title": "Partner Name",
            "description": "Name of the partner or client"
          },
          "session_id": {
            "type": "string",
            "title": "Session Id",
            "description": "Unique session identifier"
          },
          "tenant_id": {
            "type": "string",
            "title": "Tenant Id",
            "description": "Unique tenant identifier"
          },
          "bank_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Bank Name",
            "description": "Bank name (alias for partner_name)"
          },
          "customer_type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ReconciliationCustomerTypeEnum"
              },
              {
                "type": "null"
              }
            ],
            "description": "Type of customer"
          },
          "card_scheme": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CardSchemeEnum"
              },
              {
                "type": "null"
              }
            ],
            "description": "Card scheme (e.g. 'visa', 'mastercard', 'verve')"
          },
          "bank_service": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ServiceType"
              },
              {
                "type": "null"
              }
            ],
            "description": "Optional bank service"
          },
          "is_switch": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Switch",
            "description": "Set to true to indicate Interswitch."
          },
          "switch_type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Switch Type",
            "description": "Switch type identifier."
          },
          "is_scheduled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Scheduled",
            "description": "Indicates if this reconciliation was triggered by a schedule."
          },
          "branch_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Branch Id",
            "description": "Unique branch identifier"
          },
          "branch_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Branch Name",
            "description": "Name of the bank branch"
          },
          "existing_session_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Existing Session Id",
            "description": "Existing Session Id"
          },
          "last_processed_step": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Processed Step",
            "description": "Last processed step"
          },
          "period_start_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period Start Date",
            "description": "Start date of the period (YYYY-MM-DD)"
          },
          "period_end_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period End Date",
            "description": "End date of the period (YYYY-MM-DD)"
          },
          "on_existing_action": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ReconciliationMode"
              },
              {
                "type": "null"
              }
            ],
            "default": "overwrite"
          },
          "reconciliation_flow": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Reconciliation Flow",
            "description": "NIP reconciliation flow direction: 'inward' | 'outward'. Only meaningful when customer_type is commercial_bank and the template's service is ServiceType.NIP."
          },
          "is_settlement": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Settlement",
            "description": "Deprecated -- ignored. NIP reconciliation is now classified by customer_type + the template's service (ServiceType.NIP), not by this flag. Accepted here only so older callers that still send it aren't rejected; it has no effect on dispatch."
          },
          "settings": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Settings",
            "description": "Settings overrides (partial)"
          },
          "template": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Template",
            "description": "Template configuration (full or partial)"
          },
          "ingress_task_id": {
            "type": "string",
            "title": "Ingress Task Id",
            "description": "Ingress task identifier"
          },
          "records_create_task_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Records Create Task Id",
            "description": "Records create task identifier"
          },
          "gl_reversal_task_id": {
            "type": "string",
            "title": "Gl Reversal Task Id",
            "description": "GL reversal task identifier"
          },
          "reconciliation_task_id": {
            "type": "string",
            "title": "Reconciliation Task Id",
            "description": "Reconciliation task identifier"
          },
          "matched_records_task_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Matched Records Task Id",
            "description": "Matched records task identifier"
          },
          "summary_task_id": {
            "type": "string",
            "title": "Summary Task Id",
            "description": "Summary task identifier"
          },
          "exclude_debits_from_rate": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exclude Debits From Rate",
            "description": "Exclude debit-only and fee transactions from match rate denominator",
            "default": true
          },
          "exception_analysis_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Exception Analysis Enabled",
            "description": "Run exception clustering on unmatched records after reconciliation completes",
            "default": true
          },
          "gl_file_url": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Gl File Url",
            "description": "URLs/paths to General Ledger files."
          },
          "bank_file_url": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Bank File Url",
            "description": "List of URLs or paths to Bank Statement files"
          },
          "mappings": {
            "items": {
              "$ref": "#/components/schemas/ColumnMapping"
            },
            "type": "array",
            "title": "Mappings",
            "description": "List of column mappings"
          },
          "others": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/OthersMapping"
              },
              {
                "type": "null"
              }
            ],
            "description": "Other mappings for GL and Statement"
          },
          "event_dates": {
            "anyOf": [
              {
                "items": {
                  "$ref": "#/components/schemas/EventDate"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Event Dates",
            "description": "Calendar event/holiday date ranges for settlement date calculation"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "partner_id",
          "partner_name",
          "session_id",
          "tenant_id",
          "ingress_task_id",
          "gl_reversal_task_id",
          "reconciliation_task_id",
          "summary_task_id",
          "bank_file_url",
          "mappings"
        ],
        "title": "IngestionRequest",
        "description": "Money reconciliation \u2014 GL against a bank statement (bank / payment / commercial).\n\nThe flow comes from `customer_type` alone, as it always did. Holdings (asset, unit)\nare NOT reconciled here: they have their own endpoint and their own model, so none of\ntheir fields \u2014 portfolios, the custodian, the asset classes \u2014 are accepted on this\none, and a caller sending them gets a 422 rather than a session in the wrong tables.",
        "example": {
          "bank_file_url": [
            "https://storage.googleapis.com/.../bank.xlsx"
          ],
          "branch_name": "Head Quarters",
          "customer_type": "mfb",
          "existing_session_id": "...",
          "gl_file_url": [
            "https://storage.googleapis.com/.../gl.xlsx"
          ],
          "gl_reversal_task_id": "...",
          "ingress_task_id": "...",
          "is_scheduled": false,
          "is_switch": true,
          "mappings": [
            {
              "gl_title": "Transaction Date",
              "statement_title": "Transaction Date",
              "system": "Transaction Date"
            }
          ],
          "matched_records_task_id": "...",
          "others": {
            "gl": [],
            "statement": [
              "SN"
            ]
          },
          "partner_id": "569bba73-ea59-4712-b3ae-fecc30549e8f",
          "partner_name": "Access Bank",
          "period_end_date": "2026-01-23",
          "period_start_date": "2026-01-23",
          "reconciliation_task_id": "...",
          "records_create_task_id": "...",
          "session_id": "...",
          "settings": {
            "max_days_backward_search": 5,
            "max_days_forward_search": 5
          },
          "summary_task_id": "...",
          "template": {
            "matchingMethod": "line_by_line",
            "maxDaysBackwardSearch": 1,
            "maxDaysForwardSearch": 2,
            "reversalMaxDaysBackwardSearch": 2,
            "reversalMaxDaysForwardSearch": 3,
            "service": "transfers"
          },
          "tenant_id": "abbey"
        }
      },
      "OthersMapping": {
        "properties": {
          "gl": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Gl",
            "description": "Other GL column mappings"
          },
          "statement": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Statement",
            "description": "Other Statement column mappings"
          }
        },
        "type": "object",
        "title": "OthersMapping"
      },
      "PortfolioInput": {
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Id",
            "description": "Software-side portfolio id"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Portfolio name, e.g. 'Private Banking Notes'"
          },
          "code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Code",
            "description": "Portfolio short code, e.g. 'PBN'"
          },
          "url": {
            "type": "string",
            "title": "Url",
            "description": "Holdings file for this portfolio. Send a list of files instead and the portfolio is split into one object per file, each stamped the same."
          }
        },
        "type": "object",
        "required": [
          "name",
          "url"
        ],
        "title": "PortfolioInput",
        "description": "One internal portfolio and the holdings file that carries it.\n\n`id` is the software-side portfolio id and the identity: every row of `url` is\nstamped with it, and it comes back on each match/break as `portfolioId`. `name` is\nwhat the file's own labels and the custodian report's participant labels are\nmatched against, and `code` is that portfolio's short code ('PBN') \u2014 the custodian\nfrequently labels a fund by it, so supplying it makes that alignment exact instead\nof leaving it to an acronym heuristic."
      },
      "ReconciliationCustomerTypeEnum": {
        "type": "string",
        "enum": [
          "mfb",
          "commercial_bank",
          "payment_provider",
          "lender",
          "fund_manager"
        ],
        "title": "ReconciliationCustomerTypeEnum"
      },
      "ReconciliationMode": {
        "type": "string",
        "enum": [
          "merge",
          "overwrite",
          "stop"
        ],
        "title": "ReconciliationMode"
      },
      "SecondaryMapping": {
        "properties": {
          "gl_title": {
            "type": "string",
            "title": "Gl Title"
          },
          "statement_title": {
            "type": "string",
            "title": "Statement Title"
          }
        },
        "type": "object",
        "required": [
          "gl_title",
          "statement_title"
        ],
        "title": "SecondaryMapping"
      },
      "ServiceType": {
        "type": "string",
        "enum": [
          "card_settlement",
          "transfers",
          "cash_deposits",
          "pos_deposits",
          "pos",
          "ussd",
          "bill_payments",
          "atm",
          "nip",
          "other"
        ],
        "title": "ServiceType",
        "description": "Service types for reconciliation templates"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      }
    }
  }
}
