--- components: schemas: AccountActivitySnapshotResponse: description: Account activity snapshot — periodic summary of debit/credit activity for an AccountHolder. Maps to ISO 20022 camt:052 (intraday account report) and camt:053 (account statement). AML fields (flagged_for_review, review_reason, sar_reference) support FinCEN SAR filing under 31 CFR §1020.320. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 closing_balance: 0 currency: '' external_reference: '' flagged_for_review: false id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 opening_balance: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 period_end: 2020-04-20T16:20:00Z period_start: 2020-04-20T16:20:00Z review_reason: '' sar_reference: '' snapshot_type: intraday status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_credit_count: 0 total_debit_amount: 0 total_debit_count: 0 transaction_count: 0 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: closing_balance: description: Balance at period end in minor currency units (camt:053 ClosingBooked) nullable: true type: integer x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: external_reference: description: Caller-supplied idempotency key (unique per tenant when set) nullable: true type: string x-struct: x-validate: flagged_for_review: description: AML review flag — true when activity patterns exceed FinCEN AML thresholds (31 CFR §1020.320 SAR requirements) type: boolean x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: ledger_account_id: description: LedgerAccount scoping this snapshot (chart-of-accounts view) format: uuid nullable: true type: string x-struct: x-validate: opening_balance: description: Balance at period start in minor currency units (camt:053 OpeningBooked) nullable: true type: integer x-struct: x-validate: payment_account_id: description: PaymentAccount scoping this snapshot (camt:052/053 ) format: uuid nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: review_reason: description: Human-readable description of why this snapshot was flagged for AML review nullable: true type: string x-struct: x-validate: sar_reference: description: SAR (Suspicious Activity Report) filing reference (FinCEN SAR form 111) nullable: true type: string x-struct: x-validate: snapshot_type: description: Reporting period type — intraday maps to camt:052 (on-demand report); daily/weekly/monthly map to camt:053 (periodic statement) enum: - intraday - daily - weekly - monthly type: string x-struct: x-validate: status: description: Snapshot lifecycle status — pending (queued), computed (aggregates ready), published (sent to downstream / regulatory reporting) enum: - pending - computed - published nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount in minor currency units (camt:052/053 TtlCdtNtries Amt) type: integer x-struct: x-validate: total_credit_count: description: Number of credit entries in the period (camt:052/053 CdtNb) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount in minor currency units (camt:052/053 TtlDbtNtries Amt) type: integer x-struct: x-validate: total_debit_count: description: Number of debit entries in the period (camt:052/053 DbtNb) type: integer x-struct: x-validate: transaction_count: description: Total number of transactions (debit + credit) in the period type: integer x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - snapshot_type - period_start - period_end - account_holder_id - tenant_id title: AccountActivitySnapshotResponse type: object x-order: - id - snapshot_type - period_start - period_end - opening_balance - closing_balance - currency - total_debit_count - total_credit_count - total_debit_amount - total_credit_amount - transaction_count - status - flagged_for_review - review_reason - sar_reference - external_reference - account_holder_id - payment_account_id - ledger_account_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotResponse x-validate: PartyActivitySnapshotListResponse: description: Paginated list of party_activity_snapshots properties: data: description: List of party_activity_snapshots items: $ref: '#/components/schemas/PartyActivitySnapshotResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: PartyActivitySnapshotListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotListResponse x-validate: TenantResponse: description: Tenant schema for multi-tenancy example: enabled_regimes: - "" id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' slug: '' status: active tenant_type: platform updated_at: 2020-04-20T16:20:00Z properties: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: id: format: uuid type: string x-struct: x-validate: inserted_at: format: date-time type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: slug: nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - inactive type: string x-struct: x-validate: tenant_type: enum: - platform - standard type: string x-struct: x-validate: updated_at: format: date-time type: string x-struct: x-validate: readOnly: true required: - name - tenant_type title: TenantResponse type: object x-order: - id - name - slug - status - tenant_type - metadata - enabled_regimes - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.TenantResponse x-validate: BlocklistEntryResponse: description: Blocklist entry for account holder screening with tenant isolation example: active: false added_by_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 entry_type: exact id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z reason: '' scope: first_name tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 term: '' updated_at: 2020-04-20T16:20:00Z properties: active: default: true type: boolean x-struct: x-validate: added_by_id: format: uuid nullable: true type: string x-struct: x-validate: entry_type: enum: - exact - regex type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: term: type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - scope - entry_type - term - tenant_id title: BlocklistEntryResponse type: object x-order: - id - scope - entry_type - term - reason - active - added_by_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryResponse x-validate: BlocklistMatchRequest: description: One internal blocklist hit. false_positive_qualifier persists reviewer decisions across re-screenings. blocklist_updated_at lets reviewers re-evaluate overrides after list updates. Request example: blocklist_updated_at: 2020-04-20T16:20:00Z false_positive_qualifier: none match_type: exact matched_term: '' reason: '' review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 scope: first_name properties: blocklist_updated_at: format: date-time nullable: true type: string x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: match_type: enum: - exact - regex type: string x-struct: x-validate: matched_term: type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: required: - matched_term - match_type - scope title: BlocklistMatchRequest type: object writeOnly: true x-order: - matched_term - match_type - scope - reason - blocklist_updated_at - false_positive_qualifier - review_notes - reviewed_by_user_id - reviewed_at x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistMatchRequest x-validate: TransactionRequest: description: 'Payment transaction — one row per payment instruction or transfer event. Covers pain:001 (initiation), pacs:008 (interbank), pacs:002 (status), pacs:004 (return), camt:054 (booking notification). FATF Rec 16: debtor/creditor payment accounts must be verified before settlement. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' debtor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 debtor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 end_to_end_id: '' external_id: '' instruction_id: '' ledger_entry_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requested_execution_date: 2020-04-20 settlement_date: 2020-04-20 status: pending status_reason_code: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 transaction_type: credit_transfer uetr: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (cents) — always positive type: integer x-struct: x-validate: compliance_screening_id: description: ComplianceScreening result for this transaction (auth:018 / camt:998) format: uuid nullable: true type: string x-struct: x-validate: creditor_counterparty_id: description: Creditor (payee) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: creditor_payment_account_id: description: Creditor (payee) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) type: string x-struct: x-validate: debtor_counterparty_id: description: Debtor (payer) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: debtor_payment_account_id: description: Debtor (payer) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: end_to_end_id: description: pain:001 EndToEndId — set by originating party, immutable once set nullable: true type: string x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: instruction_id: description: pain:001 TxId — instruction ID from the payment initiation message nullable: true type: string x-struct: x-validate: ledger_entry_id: description: LedgerEntry created by this transaction (camt:052/053 Ntry) format: uuid nullable: true type: string x-struct: x-validate: requested_execution_date: description: Requested execution date (pain:001 ReqdExctnDt) format: date nullable: true type: string x-struct: x-validate: settlement_date: description: Actual settlement date (pacs:008 IntrBkSttlmDt / camt:054 BookgDt) format: date nullable: true type: string x-struct: x-validate: status: description: Payment lifecycle status (pain:002 / pacs:002 TxSts) enum: - pending - accepted - settled - rejected - reversed - cancelled nullable: true type: string x-struct: x-validate: status_reason_code: description: pacs:002 TxSts reason code (e.g. RJCT, ACCP, ACSC, PDNG) nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: transaction_type: description: ISO 20022 payment instruction type enum: - credit_transfer - direct_debit - card_payment - refund - reversal - internal_transfer type: string x-struct: x-validate: uetr: description: SWIFT gpi UETR (Unique End-to-End Transaction Reference — ISO 20022). Globally unique. nullable: true type: string x-struct: x-validate: required: - transaction_type - amount - currency - account_holder_id - tenant_id title: TransactionRequest type: object writeOnly: true x-order: - transaction_type - status - amount - currency - end_to_end_id - uetr - instruction_id - status_reason_code - requested_execution_date - settlement_date - external_id - account_holder_id - debtor_payment_account_id - creditor_payment_account_id - debtor_counterparty_id - creditor_counterparty_id - ledger_entry_id - compliance_screening_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.TransactionRequest x-validate: BlocklistEntryListResponse: description: Paginated list of blocklist_entries properties: data: description: List of blocklist_entries items: $ref: '#/components/schemas/BlocklistEntryResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: BlocklistEntryListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryListResponse x-validate: RiskClassificationRequest: description: Formal risk classification record for an AccountHolder. Drives the LedgerAccount limit cascade. Exactly one is_active=true record exists per (holder, tenant) at a time. Maps to ISO 20022 auth:018 (CustomerRiskAssessment) and FATF Rec 10 (risk-based CDD). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 classification_reason: '' classified_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 effective_from: 2020-04-20 effective_until: 2020-04-20 is_active: false notes: '' risk_level: low tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: classification_reason: description: Human-readable justification for the classification type: string x-struct: x-validate: classified_by_user_id: description: User who performed the classification (nil = auto-classified by engine) format: uuid nullable: true type: string x-struct: x-validate: compliance_screening_id: description: ComplianceScreening that drove this classification format: uuid nullable: true type: string x-struct: x-validate: effective_from: description: Start date of the classification (inclusive) format: date type: string x-struct: x-validate: effective_until: description: End date of the classification (exclusive), nil = open-ended format: date nullable: true type: string x-struct: x-validate: is_active: default: true description: True when this is the current active classification for the holder type: boolean x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: risk_level: description: Risk level driving the LedgerAccount limit cascade enum: - low - medium - high - very_high type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - risk_level - classification_reason - effective_from - tenant_id title: RiskClassificationRequest type: object writeOnly: true x-order: - account_holder_id - risk_level - classification_reason - effective_from - effective_until - is_active - classified_by_user_id - compliance_screening_id - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RiskClassificationRequest x-validate: LinkedLedgerAccountRequest: description: Edge in the LedgerAccount tree. Read-only — populated by a database trigger on LedgerAccount insert. Application code never writes to this table. Request example: {} properties: {} title: LinkedLedgerAccountRequest type: object writeOnly: true x-order: [] x-struct: Elixir.AtomicFi.OpenApiSchema.LinkedLedgerAccountRequest x-validate: UserResponse: description: User schema example: confirmed_at: 2020-04-20T16:20:00Z email: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: confirmed_at: format: date-time nullable: true type: string x-struct: x-validate: email: type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - email - tenant_id title: UserResponse type: object x-order: - id - email - confirmed_at - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.UserResponse x-validate: ApiInfoResponse: description: API information with version and database connectivity status properties: database_status: enum: - connected - disconnected example: connected type: string x-struct: x-validate: status: enum: - ok - error example: ok type: string x-struct: x-validate: timestamp: example: 2026-02-04T12:34:56.789Z format: date-time type: string x-struct: x-validate: version: example: 0.1.0 type: string x-struct: x-validate: required: - status - version - database_status - timestamp title: ApiInfoResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ApiInfoResponse x-validate: ErrorResponse: description: Error response example: errors: detail: Not found properties: errors: additionalProperties: oneOf: - type: string x-struct: x-validate: - items: type: string x-struct: x-validate: type: array x-struct: x-validate: x-struct: x-validate: description: Error details - values can be strings or arrays of strings (for validation errors) type: object x-struct: x-validate: title: ErrorResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ErrorResponse x-validate: WatchmanBusinessRequest: description: Normalized Watchman business block Request example: dissolved_date: '' incorporation_date: '' name: '' registration_number: '' properties: dissolved_date: nullable: true type: string x-struct: x-validate: incorporation_date: nullable: true type: string x-struct: x-validate: name: nullable: true type: string x-struct: x-validate: registration_number: nullable: true type: string x-struct: x-validate: title: WatchmanBusinessRequest type: object writeOnly: true x-order: - name - registration_number - incorporation_date - dissolved_date x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanBusinessRequest x-validate: ChangesetErrors: description: Validation error response in JSON:API format (from OpenApiSpex v2) example: errors: - detail: can't be blank source: pointer: /name title: Invalid value - detail: is invalid source: pointer: /type title: Invalid value properties: errors: description: Array of validation error objects items: properties: detail: description: Error message type: string x-struct: x-validate: source: properties: pointer: description: JSON pointer to the field type: string x-struct: x-validate: type: object x-struct: x-validate: title: description: Error title type: string x-struct: x-validate: type: object x-struct: x-validate: type: array x-struct: x-validate: title: ChangesetErrors type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors x-validate: WatchmanAddressResponse: description: Normalized Watchman address entry example: city: '' country: '' line1: '' line2: '' postal_code: '' region: '' type: '' properties: city: nullable: true type: string x-struct: x-validate: country: nullable: true type: string x-struct: x-validate: line1: nullable: true type: string x-struct: x-validate: line2: nullable: true type: string x-struct: x-validate: postal_code: nullable: true type: string x-struct: x-validate: region: nullable: true type: string x-struct: x-validate: type: nullable: true type: string x-struct: x-validate: readOnly: true title: WatchmanAddressResponse type: object x-order: - line1 - line2 - city - region - postal_code - country - type x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanAddressResponse x-validate: RoleListResponse: description: Paginated list of roles properties: data: description: List of roles items: $ref: '#/components/schemas/RoleResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: RoleListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.RoleListResponse x-validate: AddressResponse: description: Address information (Watchman format) example: city: '' country: '' line1: '' line2: '' postalCode: '' state: '' properties: city: type: string x-struct: x-validate: country: type: string x-struct: x-validate: line1: type: string x-struct: x-validate: line2: type: string x-struct: x-validate: postalCode: type: string x-struct: x-validate: state: type: string x-struct: x-validate: readOnly: true title: AddressResponse type: object x-order: - city - country - line1 - line2 - postalCode - state x-struct: Elixir.AtomicFi.OpenApiSchema.AddressResponse x-validate: LedgerEntryListResponse: description: Paginated list of ledger_entries properties: data: description: List of ledger_entries items: $ref: '#/components/schemas/LedgerEntryResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LedgerEntryListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerEntryListResponse x-validate: RiskClassificationListResponse: description: Paginated list of risk_classifications properties: data: description: List of risk_classifications items: $ref: '#/components/schemas/RiskClassificationResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: RiskClassificationListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.RiskClassificationListResponse x-validate: ApiInfoErrorResponse: description: API info error response when database check fails properties: database_status: enum: - disconnected example: disconnected type: string x-struct: x-validate: error: example: Database connection failed type: string x-struct: x-validate: status: enum: - error example: error type: string x-struct: x-validate: timestamp: example: 2026-02-04T12:34:56.789Z format: date-time type: string x-struct: x-validate: version: example: 0.1.0 type: string x-struct: x-validate: required: - status - version - database_status - error - timestamp title: ApiInfoErrorResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ApiInfoErrorResponse x-validate: LedgerAccountBalanceListResponse: description: Paginated list of ledger_account_balances properties: data: description: List of ledger_account_balances items: $ref: '#/components/schemas/LedgerAccountBalanceResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LedgerAccountBalanceListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountBalanceListResponse x-validate: BlocklistEntryRequest: description: Blocklist entry for account holder screening with tenant isolation Request example: active: false added_by_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 entry_type: exact reason: '' scope: first_name tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 term: '' properties: active: default: true type: boolean x-struct: x-validate: added_by_id: format: uuid nullable: true type: string x-struct: x-validate: entry_type: enum: - exact - regex type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: term: type: string x-struct: x-validate: required: - scope - entry_type - term - tenant_id title: BlocklistEntryRequest type: object writeOnly: true x-order: - scope - entry_type - term - reason - active - added_by_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryRequest x-validate: RiskClassificationResponse: description: Formal risk classification record for an AccountHolder. Drives the LedgerAccount limit cascade. Exactly one is_active=true record exists per (holder, tenant) at a time. Maps to ISO 20022 auth:018 (CustomerRiskAssessment) and FATF Rec 10 (risk-based CDD). example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 classification_reason: '' classified_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 effective_from: 2020-04-20 effective_until: 2020-04-20 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z is_active: false notes: '' risk_level: low tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: classification_reason: description: Human-readable justification for the classification type: string x-struct: x-validate: classified_by_user_id: description: User who performed the classification (nil = auto-classified by engine) format: uuid nullable: true type: string x-struct: x-validate: compliance_screening_id: description: ComplianceScreening that drove this classification format: uuid nullable: true type: string x-struct: x-validate: effective_from: description: Start date of the classification (inclusive) format: date type: string x-struct: x-validate: effective_until: description: End date of the classification (exclusive), nil = open-ended format: date nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: is_active: default: true description: True when this is the current active classification for the holder type: boolean x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: risk_level: description: Risk level driving the LedgerAccount limit cascade enum: - low - medium - high - very_high type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - risk_level - classification_reason - effective_from - tenant_id title: RiskClassificationResponse type: object x-order: - id - account_holder_id - risk_level - classification_reason - effective_from - effective_until - is_active - classified_by_user_id - compliance_screening_id - notes - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.RiskClassificationResponse x-validate: ControlLimitRequest: description: 'One control-limit line: a cap for a `{period, direction}` pair plus the rule that set it. Embedded inside `limits_at_entry[]` on LedgerEntry / LedgerAccountBalance responses. Request' example: cap: 0 direction: debit period: daily rule: '' properties: cap: description: Cap in minor currency units; null = unconstrained. nullable: true type: integer x-struct: x-validate: direction: enum: - debit - credit type: string x-struct: x-validate: period: enum: - daily - weekly - monthly - yearly type: string x-struct: x-validate: rule: description: Name of the rule (engine) that set this cap; null if unset. nullable: true type: string x-struct: x-validate: required: - period - direction title: ControlLimitRequest type: object writeOnly: true x-order: - period - direction - cap - rule x-struct: Elixir.AtomicFi.OpenApiSchema.ControlLimitRequest x-validate: UserListResponse: description: Paginated list of users properties: data: description: List of users items: $ref: '#/components/schemas/UserResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: UserListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.UserListResponse x-validate: SessionRequest: description: Authentication session. Request fields (writeOnly) carry credentials for POST /api/sessions. Response fields (readOnly) describe the resolved session. Request example: email: '' expires_in: 60 password: a tenant_slug: '' properties: email: format: email type: string writeOnly: true x-struct: x-validate: expires_in: description: Bearer session duration in seconds. Default 86400 (24h). maximum: 2592000 minimum: 60 nullable: true type: integer writeOnly: true x-struct: x-validate: password: format: password minLength: 1 type: string writeOnly: true x-struct: x-validate: tenant_slug: type: string writeOnly: true x-struct: x-validate: required: - email - password - tenant_slug title: SessionRequest type: object writeOnly: true x-order: - email - password - tenant_slug - expires_in x-struct: Elixir.AtomicFi.OpenApiSchema.SessionRequest x-validate: AccountHolderResponse: description: Account holder — the MDM subject controlling an account. All PII lives in the linked LegalEntity (ISO 20022 acmt:007 / acmt:019). POST creates the LegalEntity atomically via the nested `legal_entity` object — the LE link is immutable post-create (LE carries the FK, not AH). To replace LE PII content, use `PUT /api/account-holders/:id/legal-entity`. example: account_holder_number: '' account_holder_type: individual beneficial_owners: - enabled_currencies: - "" enabled_regimes: - "" external_id: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z kyc_status: not_started last_reviewed_at: 2020-04-20T16:20:00Z legal_entity: onboarded_at: 2020-04-20T16:20:00Z risk_level: low status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_number: nullable: true type: string x-struct: x-validate: account_holder_type: enum: - individual - business - trust - nonprofit type: string x-struct: x-validate: beneficial_owners: items: $ref: '#/components/schemas/BeneficialOwnerResponse' readOnly: true type: array x-struct: x-validate: enabled_currencies: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: kyc_status: enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: last_reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityResponse' onboarded_at: format: date-time nullable: true type: string x-struct: x-validate: risk_level: enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: status: enum: - pending - active - suspended - closed - flagged nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_type title: AccountHolderResponse type: object x-order: - id - legal_entity - external_id - account_holder_type - status - kyc_status - risk_level - enabled_currencies - enabled_regimes - account_holder_number - onboarded_at - last_reviewed_at - tenant_id - inserted_at - updated_at - beneficial_owners x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderResponse x-validate: LegalEntityAddressRequest: description: Address record for a legal entity Request example: address_types: - business country: '' line1: '' line2: '' locality: '' postal_code: '' primary: false region: '' properties: address_types: items: enum: - business - mailing - residential - po_box - other type: string x-struct: x-validate: type: array x-struct: x-validate: country: nullable: true type: string x-struct: x-validate: line1: nullable: true type: string x-struct: x-validate: line2: nullable: true type: string x-struct: x-validate: locality: nullable: true type: string x-struct: x-validate: postal_code: nullable: true type: string x-struct: x-validate: primary: nullable: true type: boolean x-struct: x-validate: region: nullable: true type: string x-struct: x-validate: required: - address_types title: LegalEntityAddressRequest type: object writeOnly: true x-order: - address_types - primary - line1 - line2 - locality - region - postal_code - country x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityAddressRequest x-validate: BeneficialOwnerListResponse: description: Paginated list of beneficial_owners properties: data: description: List of beneficial_owners items: $ref: '#/components/schemas/BeneficialOwnerResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: BeneficialOwnerListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerListResponse x-validate: AccountHolderRequest: description: Account holder — the MDM subject controlling an account. All PII lives in the linked LegalEntity (ISO 20022 acmt:007 / acmt:019). POST creates the LegalEntity atomically via the nested `legal_entity` object — the LE link is immutable post-create (LE carries the FK, not AH). To replace LE PII content, use `PUT /api/account-holders/:id/legal-entity`. Request example: account_holder_number: '' account_holder_type: individual chain_screening: false enabled_currencies: - "" enabled_regimes: - "" external_id: '' kyc_status: not_started last_reviewed_at: 2020-04-20T16:20:00Z legal_entity: onboarded_at: 2020-04-20T16:20:00Z risk_level: low status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_number: nullable: true type: string x-struct: x-validate: account_holder_type: enum: - individual - business - trust - nonprofit type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_currencies: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: kyc_status: enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: last_reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' onboarded_at: format: date-time nullable: true type: string x-struct: x-validate: risk_level: enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: status: enum: - pending - active - suspended - closed - flagged nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_type title: AccountHolderRequest type: object writeOnly: true x-order: - legal_entity - external_id - account_holder_type - status - kyc_status - risk_level - enabled_currencies - enabled_regimes - account_holder_number - onboarded_at - last_reviewed_at - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderRequest x-validate: BeneficialOwnerResponse: description: Beneficial owner of a corporate account holder. ≥25% ownership triggers FinCEN CDD Rule 31 CFR §1010.230 (FATF Rec 24). All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object. The LE link is immutable post-create (LE owns the FK back). To replace LE PII, use `PUT /api/beneficial-owners/:id/legal-entity`. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owner_number: '' control_type: shareholder external_id: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z legal_entity: ownership_pct: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z verification_status: pending properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owner_number: nullable: true type: string x-struct: x-validate: control_type: enum: - shareholder - director - officer - trustee type: string x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityResponse' ownership_pct: nullable: true type: number x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: verification_status: enum: - pending - verified - failed nullable: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - control_type title: BeneficialOwnerResponse type: object x-order: - id - account_holder_id - external_id - legal_entity - ownership_pct - control_type - verification_status - beneficial_owner_number - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerResponse x-validate: BeneficialOwnerRequest: description: Beneficial owner of a corporate account holder. ≥25% ownership triggers FinCEN CDD Rule 31 CFR §1010.230 (FATF Rec 24). All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object. The LE link is immutable post-create (LE owns the FK back). To replace LE PII, use `PUT /api/beneficial-owners/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owner_number: '' chain_screening: false control_type: shareholder external_id: '' legal_entity: ownership_pct: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 verification_status: pending properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owner_number: nullable: true type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: control_type: enum: - shareholder - director - officer - trustee type: string x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' ownership_pct: nullable: true type: number x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: verification_status: enum: - pending - verified - failed nullable: true type: string x-struct: x-validate: required: - account_holder_id - control_type title: BeneficialOwnerRequest type: object writeOnly: true x-order: - account_holder_id - external_id - legal_entity - ownership_pct - control_type - verification_status - beneficial_owner_number - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerRequest x-validate: LedgerAccountRequest: description: Control account in the double-entry payments ledger. `side` is the normal balance (credit-normal | debit-normal); `balance` is the running net (credits − debits), trigger-maintained. Hierarchy is captured solely in the flat ancestor_ids array; regime is a generic discriminator. Control limits live on ledger_account_balances.limits. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' la_type: account_holder_root ledger_account_number: '' ledger_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 regime: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: counterparty_id: description: Counterparty this account belongs to (NULL on master roots and PaymentAccount accounts). format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from parent Ledger. type: string x-struct: x-validate: la_type: description: Position of this row in the LedgerAccount tree. Combined with regime, determines whether this row is an aggregation root or a regime-specific child. Enforced by the ledger_accounts_la_type_shape_check CHECK constraint. enum: - account_holder_root - account_holder_regime_root - counter_party_root - counter_party_regime_root - account_holder_payment_account_root - account_holder_payment_account_regime_root - counter_party_payment_account_root - counter_party_payment_account_regime_root type: string x-struct: x-validate: ledger_account_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_id: format: uuid type: string x-struct: x-validate: payment_account_id: description: PaymentAccount this account belongs to (NULL on master roots). format: uuid nullable: true type: string x-struct: x-validate: regime: description: Generic regime discriminator (regulatory regime, fraud regime, …). Regime leaves carry the real regime name; aggregation roots carry the sentinel "root". type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_id - currency - regime title: LedgerAccountRequest type: object writeOnly: true x-order: - account_holder_id - ledger_id - currency - regime - status - ledger_account_number - payment_account_id - counterparty_id - la_type - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountRequest x-validate: KycRequirementRequest: description: 'KYC verification requirement — one row per compliance check at a given FATF scope. `account_holder_id` is always the MDM subject; `legal_entity_id` is the identity being verified. Natural key: (account_holder_id, legal_entity_id, scope, requirement_type). Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 deadline: 2020-04-20 document_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 kyc_requirement_number: '' legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requirement_type: identity_document scope: account_holder status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: deadline: format: date nullable: true type: string x-struct: x-validate: document_id: format: uuid nullable: true type: string x-struct: x-validate: kyc_requirement_number: nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: requirement_type: enum: - identity_document - proof_of_address - source_of_funds - business_relationship - pep_declaration - ubo_declaration - purpose_of_payment type: string x-struct: x-validate: scope: enum: - account_holder - counterparty - payment_account - beneficial_owner type: string x-struct: x-validate: status: enum: - pending - submitted - under_review - approved - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - scope - requirement_type - account_holder_id - legal_entity_id - tenant_id title: KycRequirementRequest type: object writeOnly: true x-order: - scope - requirement_type - status - deadline - kyc_requirement_number - account_holder_id - legal_entity_id - document_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.KycRequirementRequest x-validate: LedgerListResponse: description: Paginated list of ledgers properties: data: description: List of ledgers items: $ref: '#/components/schemas/LedgerResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LedgerListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerListResponse x-validate: LegalEntityPhoneNumberResponse: description: Phone number record for a legal entity. Stored in E.164 format. example: id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 phone_number: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: legal_entity_id: format: uuid readOnly: true type: string x-struct: x-validate: phone_number: type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - phone_number title: LegalEntityPhoneNumberResponse type: object x-order: - id - legal_entity_id - phone_number - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityPhoneNumberResponse x-validate: LedgerResponse: description: ISO 20022 camt:052/camt:053 chart-of-accounts container — one per AccountHolder per currency. Balance is derived on-read by summing child LedgerAccount.balance values. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z ledger_number: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code (e.g. USD). Authoritative for the entire ledger hierarchy. type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: ledger_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - currency title: LedgerResponse type: object x-order: - id - account_holder_id - currency - status - ledger_number - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerResponse x-validate: LegalEntityListResponse: description: Paginated list of legal_entities properties: data: description: List of legal_entities items: $ref: '#/components/schemas/LegalEntityResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LegalEntityListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityListResponse x-validate: KycRequirementResponse: description: 'KYC verification requirement — one row per compliance check at a given FATF scope. `account_holder_id` is always the MDM subject; `legal_entity_id` is the identity being verified. Natural key: (account_holder_id, legal_entity_id, scope, requirement_type).' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 deadline: 2020-04-20 document_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z kyc_requirement_number: '' legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requirement_type: identity_document scope: account_holder status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: deadline: format: date nullable: true type: string x-struct: x-validate: document_id: format: uuid nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: kyc_requirement_number: nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: requirement_type: enum: - identity_document - proof_of_address - source_of_funds - business_relationship - pep_declaration - ubo_declaration - purpose_of_payment type: string x-struct: x-validate: scope: enum: - account_holder - counterparty - payment_account - beneficial_owner type: string x-struct: x-validate: status: enum: - pending - submitted - under_review - approved - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - scope - requirement_type - account_holder_id - legal_entity_id - tenant_id title: KycRequirementResponse type: object x-order: - id - scope - requirement_type - status - deadline - kyc_requirement_number - account_holder_id - legal_entity_id - document_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.KycRequirementResponse x-validate: LegalEntityPhoneNumberRequest: description: Phone number record for a legal entity. Stored in E.164 format. Request example: phone_number: '' properties: phone_number: type: string x-struct: x-validate: required: - phone_number title: LegalEntityPhoneNumberRequest type: object writeOnly: true x-order: - phone_number x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityPhoneNumberRequest x-validate: ContactResponse: description: Contact information (Watchman format) example: emailAddresses: - "" faxNumbers: - "" phoneNumbers: - "" websites: - "" properties: emailAddresses: items: type: string x-struct: x-validate: type: array x-struct: x-validate: faxNumbers: items: type: string x-struct: x-validate: type: array x-struct: x-validate: phoneNumbers: items: type: string x-struct: x-validate: type: array x-struct: x-validate: websites: items: type: string x-struct: x-validate: type: array x-struct: x-validate: readOnly: true title: ContactResponse type: object x-order: - emailAddresses - faxNumbers - phoneNumbers - websites x-struct: Elixir.AtomicFi.OpenApiSchema.ContactResponse x-validate: PaymentAccountRequest: description: 'Payment account — one row per payment instrument linked to an AccountHolder (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer rule compliance. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 account_number: '' account_type: bank_account bank_name: '' card_pan: '' counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' enabled_regimes: - "" external_id: '' iban: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_number: '' routing_number: '' status: active swift_bic: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 wallet_address: '' wallet_chain: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: account_number: description: Bank account number (PCI-DSS sensitive — tokenise before storing) nullable: true type: string x-struct: x-validate: account_type: enum: - bank_account - card - wallet - crypto_wallet type: string x-struct: x-validate: bank_name: description: Name of the account's bank nullable: true type: string x-struct: x-validate: card_pan: description: Card PAN last-4 or token (PCI-DSS — never store raw PAN) nullable: true type: string x-struct: x-validate: counterparty_id: format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: iban: description: International Bank Account Number (IBAN) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: payment_account_number: description: Opaque internal payment account number nullable: true type: string x-struct: x-validate: routing_number: description: Bank routing / sort code nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - blocked nullable: true type: string x-struct: x-validate: swift_bic: description: SWIFT/BIC code of the account's bank nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: wallet_address: description: On-chain wallet address (the actual identifier funds settle to). Set together with wallet_chain when account_type = :crypto_wallet. nullable: true type: string x-struct: x-validate: wallet_chain: description: Blockchain / asset ticker the wallet_address lives on (e.g. "BTC", "ETH", "TRON"). Disambiguates same-format addresses across chains. nullable: true type: string x-struct: x-validate: required: - account_type - account_holder_id - tenant_id title: PaymentAccountRequest type: object writeOnly: true x-order: - account_type - status - currency - account_number - routing_number - iban - swift_bic - bank_name - card_pan - wallet_address - wallet_chain - payment_account_number - external_id - account_holder_id - legal_entity_id - counterparty_id - ledger_account_id - enabled_regimes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountRequest x-validate: SanctionsMatchResponse: description: 'One Watchman / OFAC sanctions match. false_positive_qualifier persists reviewer decisions across re-screenings: :manual_override (human override) or :auto_suppressed (system dedup). ISO 20022 auth:018.' example: addresses: - business_data: compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 contact_data: false_positive_qualifier: none id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z list_sources: {} list_synced_at: 2020-04-20T16:20:00Z match_score: 0.0 matched_entity_type: '' matched_name: '' person_data: review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 source_data: {} source_id: '' source_list: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: addresses: items: $ref: '#/components/schemas/WatchmanAddressResponse' type: array x-struct: x-validate: business_data: $ref: '#/components/schemas/WatchmanBusinessResponse' compliance_screening_id: format: uuid readOnly: true type: string x-struct: x-validate: contact_data: $ref: '#/components/schemas/WatchmanContactResponse' false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: list_sources: nullable: true type: object x-struct: x-validate: list_synced_at: format: date-time nullable: true type: string x-struct: x-validate: match_score: format: float type: number x-struct: x-validate: matched_entity_type: nullable: true type: string x-struct: x-validate: matched_name: type: string x-struct: x-validate: person_data: $ref: '#/components/schemas/WatchmanPersonResponse' review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: source_data: nullable: true type: object x-struct: x-validate: source_id: nullable: true type: string x-struct: x-validate: source_list: type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - matched_name - match_score - source_list title: SanctionsMatchResponse type: object x-order: - id - compliance_screening_id - matched_name - matched_entity_type - match_score - source_list - source_id - source_data - addresses - business_data - person_data - contact_data - false_positive_qualifier - review_notes - reviewed_by_user_id - reviewed_at - list_synced_at - list_sources - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.SanctionsMatchResponse x-validate: DocumentRequest: description: Compliance document — one row per supporting document for an AccountHolder (ISO 20022 acmt:007 SupportingDocument). Physical files are stored out-of-band; this record holds only the storage reference. At most one document may be primary per (account_holder_id, name) combination. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 content_type: '' description: '' document_number: '' document_type: identity_document file_key: '' file_name: '' file_size: 0 metadata: {} name: '' primary: false status: draft tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: content_type: nullable: true type: string x-struct: x-validate: description: nullable: true type: string x-struct: x-validate: document_number: nullable: true type: string x-struct: x-validate: document_type: enum: - identity_document - proof_of_address - source_of_funds - business_registration - ubo_declaration - pep_declaration - other type: string x-struct: x-validate: file_key: nullable: true type: string x-struct: x-validate: file_name: nullable: true type: string x-struct: x-validate: file_size: nullable: true type: integer x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: primary: type: boolean x-struct: x-validate: status: enum: - draft - submitted - under_review - accepted - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - document_type - name - primary - account_holder_id - tenant_id title: DocumentRequest type: object writeOnly: true x-order: - document_type - name - description - status - primary - file_key - file_name - file_size - content_type - document_number - metadata - account_holder_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.DocumentRequest x-validate: ControlLimitResponse: description: 'One control-limit line: a cap for a `{period, direction}` pair plus the rule that set it. Embedded inside `limits_at_entry[]` on LedgerEntry / LedgerAccountBalance responses.' example: cap: 0 direction: debit period: daily rule: '' properties: cap: description: Cap in minor currency units; null = unconstrained. nullable: true type: integer x-struct: x-validate: direction: enum: - debit - credit type: string x-struct: x-validate: period: enum: - daily - weekly - monthly - yearly type: string x-struct: x-validate: rule: description: Name of the rule (engine) that set this cap; null if unset. nullable: true type: string x-struct: x-validate: readOnly: true required: - period - direction title: ControlLimitResponse type: object x-order: - period - direction - cap - rule x-struct: Elixir.AtomicFi.OpenApiSchema.ControlLimitResponse x-validate: RoleRequest: description: Role schema Request example: description: '' metadata: {} name: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: description: type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - description - tenant_id title: RoleRequest type: object writeOnly: true x-order: - name - description - metadata - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RoleRequest x-validate: ApiKeyListResponse: description: Paginated list of api_keys properties: data: description: List of api_keys items: $ref: '#/components/schemas/ApiKeyResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: ApiKeyListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ApiKeyListResponse x-validate: WatchmanAddressRequest: description: Normalized Watchman address entry Request example: city: '' country: '' line1: '' line2: '' postal_code: '' region: '' type: '' properties: city: nullable: true type: string x-struct: x-validate: country: nullable: true type: string x-struct: x-validate: line1: nullable: true type: string x-struct: x-validate: line2: nullable: true type: string x-struct: x-validate: postal_code: nullable: true type: string x-struct: x-validate: region: nullable: true type: string x-struct: x-validate: type: nullable: true type: string x-struct: x-validate: title: WatchmanAddressRequest type: object writeOnly: true x-order: - line1 - line2 - city - region - postal_code - country - type x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanAddressRequest x-validate: LedgerAccountListResponse: description: Paginated list of ledger_accounts properties: data: description: List of ledger_accounts items: $ref: '#/components/schemas/LedgerAccountResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LedgerAccountListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountListResponse x-validate: WatchmanPersonResponse: description: Normalized Watchman person block example: dob: '' family_name: '' gender: '' given_name: '' nationalities: - "" properties: dob: nullable: true type: string x-struct: x-validate: family_name: nullable: true type: string x-struct: x-validate: gender: nullable: true type: string x-struct: x-validate: given_name: nullable: true type: string x-struct: x-validate: nationalities: items: type: string x-struct: x-validate: type: array x-struct: x-validate: readOnly: true title: WatchmanPersonResponse type: object x-order: - given_name - family_name - dob - gender - nationalities x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanPersonResponse x-validate: TenantListResponse: description: Paginated list of tenants properties: data: description: List of tenants items: $ref: '#/components/schemas/TenantResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: TenantListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.TenantListResponse x-validate: LegalEntityRequest: description: Shared identity record for individuals and businesses per ISO 20022 acmt:007 + FATF CDD Request example: addresses: - business_name: '' citizenship_country: '' date_formed: 2020-04-20 date_of_birth: 2020-04-20 doing_business_as_names: - "" first_name: '' identifications: - last_name: '' legal_entity_type: individual legal_structure: corporation middle_name: '' phone_numbers: - politically_exposed_person: false preferred_name: '' prefix: '' suffix: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 website: '' properties: addresses: items: $ref: '#/components/schemas/LegalEntityAddressRequest' type: array x-struct: x-validate: business_name: nullable: true type: string x-struct: x-validate: citizenship_country: nullable: true type: string x-struct: x-validate: date_formed: format: date nullable: true type: string x-struct: x-validate: date_of_birth: format: date nullable: true type: string x-struct: x-validate: doing_business_as_names: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: first_name: nullable: true type: string x-struct: x-validate: identifications: items: $ref: '#/components/schemas/LegalEntityIdentificationRequest' type: array x-struct: x-validate: last_name: nullable: true type: string x-struct: x-validate: legal_entity_type: enum: - individual - business type: string x-struct: x-validate: legal_structure: enum: - corporation - llc - non_profit - partnership - sole_proprietorship - trust - government nullable: true type: string x-struct: x-validate: middle_name: nullable: true type: string x-struct: x-validate: phone_numbers: items: $ref: '#/components/schemas/LegalEntityPhoneNumberRequest' type: array x-struct: x-validate: politically_exposed_person: nullable: true type: boolean x-struct: x-validate: preferred_name: nullable: true type: string x-struct: x-validate: prefix: nullable: true type: string x-struct: x-validate: suffix: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: website: format: uri nullable: true type: string x-struct: x-validate: required: - legal_entity_type - tenant_id title: LegalEntityRequest type: object writeOnly: true x-order: - legal_entity_type - legal_structure - business_name - doing_business_as_names - date_formed - website - first_name - middle_name - last_name - prefix - suffix - preferred_name - date_of_birth - citizenship_country - politically_exposed_person - addresses - phone_numbers - identifications - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityRequest x-validate: CounterpartyRequest: description: External payer/payee (ISO 20022 /) that an AccountHolder transacts with. All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object on POST. The LE link is immutable post-create (LE carries the FK back, not CP). To replace LE PII, use `PUT /api/counterparties/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 chain_screening: false enabled_regimes: - "" external_id: '' legal_entity: status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' status: enum: - active - suspended - blocked type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - status title: CounterpartyRequest type: object writeOnly: true x-order: - account_holder_id - legal_entity - status - external_id - enabled_regimes - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyRequest x-validate: SessionResponse: description: Authentication session. Request fields (writeOnly) carry credentials for POST /api/sessions. Response fields (readOnly) describe the resolved session. example: active: false api_key: api_key_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 bearer: '' expires_at: 2020-04-20T16:20:00Z id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} role: role_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant: tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 type: user updated_at: 2020-04-20T16:20:00Z user: user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: active: default: true readOnly: true type: boolean x-struct: x-validate: api_key: $ref: '#/components/schemas/ApiKeyResponse' api_key_id: format: uuid nullable: true readOnly: true type: string x-struct: x-validate: bearer: description: Plaintext Bearer token. Returned ONCE on POST /api/sessions. nullable: true readOnly: true type: string x-struct: x-validate: expires_at: format: date-time nullable: true readOnly: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: metadata: additionalProperties: true description: Session metadata (IP, user agent, Cloudflare headers) readOnly: true type: object x-struct: x-validate: role: $ref: '#/components/schemas/RoleResponse' role_id: format: uuid readOnly: true type: string x-struct: x-validate: tenant: $ref: '#/components/schemas/TenantResponse' tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: type: enum: - user - api readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: user: $ref: '#/components/schemas/UserResponse' user_id: format: uuid nullable: true readOnly: true type: string x-struct: x-validate: readOnly: true title: SessionResponse type: object x-order: - id - type - active - expires_at - metadata - user_id - api_key_id - role_id - tenant_id - inserted_at - updated_at - bearer - tenant - role - user - api_key x-struct: Elixir.AtomicFi.OpenApiSchema.SessionResponse x-validate: TransactionListResponse: description: Paginated list of transactions properties: data: description: List of transactions items: $ref: '#/components/schemas/TransactionResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: TransactionListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.TransactionListResponse x-validate: AccountHolderListResponse: description: Paginated list of account_holders properties: data: description: List of account_holders items: $ref: '#/components/schemas/AccountHolderResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: AccountHolderListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderListResponse x-validate: WatchmanPersonRequest: description: Normalized Watchman person block Request example: dob: '' family_name: '' gender: '' given_name: '' nationalities: - "" properties: dob: nullable: true type: string x-struct: x-validate: family_name: nullable: true type: string x-struct: x-validate: gender: nullable: true type: string x-struct: x-validate: given_name: nullable: true type: string x-struct: x-validate: nationalities: items: type: string x-struct: x-validate: type: array x-struct: x-validate: title: WatchmanPersonRequest type: object writeOnly: true x-order: - given_name - family_name - dob - gender - nationalities x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanPersonRequest x-validate: ComplianceScreeningListResponse: description: Paginated list of compliance_screenings properties: data: description: List of compliance_screenings items: $ref: '#/components/schemas/ComplianceScreeningResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: ComplianceScreeningListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.ComplianceScreeningListResponse x-validate: DocumentResponse: description: Compliance document — one row per supporting document for an AccountHolder (ISO 20022 acmt:007 SupportingDocument). Physical files are stored out-of-band; this record holds only the storage reference. At most one document may be primary per (account_holder_id, name) combination. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 content_type: '' description: '' document_number: '' document_type: identity_document file_key: '' file_name: '' file_size: 0 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' primary: false status: draft tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: content_type: nullable: true type: string x-struct: x-validate: description: nullable: true type: string x-struct: x-validate: document_number: nullable: true type: string x-struct: x-validate: document_type: enum: - identity_document - proof_of_address - source_of_funds - business_registration - ubo_declaration - pep_declaration - other type: string x-struct: x-validate: file_key: nullable: true type: string x-struct: x-validate: file_name: nullable: true type: string x-struct: x-validate: file_size: nullable: true type: integer x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: primary: type: boolean x-struct: x-validate: status: enum: - draft - submitted - under_review - accepted - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - document_type - name - primary - account_holder_id - tenant_id title: DocumentResponse type: object x-order: - id - document_type - name - description - status - primary - file_key - file_name - file_size - content_type - document_number - metadata - account_holder_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.DocumentResponse x-validate: AddressRequest: description: Address information (Watchman format) Request example: city: '' country: '' line1: '' line2: '' postalCode: '' state: '' properties: city: type: string x-struct: x-validate: country: type: string x-struct: x-validate: line1: type: string x-struct: x-validate: line2: type: string x-struct: x-validate: postalCode: type: string x-struct: x-validate: state: type: string x-struct: x-validate: title: AddressRequest type: object writeOnly: true x-order: - city - country - line1 - line2 - postalCode - state x-struct: Elixir.AtomicFi.OpenApiSchema.AddressRequest x-validate: LegalEntityIdentificationRequest: description: Identity document for a legal entity per FATF CDD requirements. Unique per (legal_entity_id, id_type). Request example: expiration_date: 2020-04-20 id_number: '' id_type: us_ssn issuing_country: '' issuing_region: '' uri: '' properties: expiration_date: format: date nullable: true type: string x-struct: x-validate: id_number: nullable: true type: string x-struct: x-validate: id_type: enum: - us_ssn - us_ein - us_itin - passport - driver_license - national_id - lei - tax_id type: string x-struct: x-validate: issuing_country: nullable: true type: string x-struct: x-validate: issuing_region: nullable: true type: string x-struct: x-validate: uri: nullable: true type: string x-struct: x-validate: required: - id_type title: LegalEntityIdentificationRequest type: object writeOnly: true x-order: - id_type - uri - id_number - issuing_country - issuing_region - expiration_date x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityIdentificationRequest x-validate: LedgerAccountResponse: description: Control account in the double-entry payments ledger. `side` is the normal balance (credit-normal | debit-normal); `balance` is the running net (credits − debits), trigger-maintained. Hierarchy is captured solely in the flat ancestor_ids array; regime is a generic discriminator. Control limits live on ledger_account_balances.limits. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 balance: 0 counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z la_type: account_holder_root ledger_account_number: '' ledger_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 linked_ledger_accounts: - payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 regime: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: balance: description: Running net balance (credits − debits) in minor currency units. Atomically maintained by the ledger_entry_propagate_to_balances trigger on entry insert/void. readOnly: true type: integer x-struct: x-validate: counterparty_id: description: Counterparty this account belongs to (NULL on master roots and PaymentAccount accounts). format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from parent Ledger. type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: la_type: description: Position of this row in the LedgerAccount tree. Combined with regime, determines whether this row is an aggregation root or a regime-specific child. Enforced by the ledger_accounts_la_type_shape_check CHECK constraint. enum: - account_holder_root - account_holder_regime_root - counter_party_root - counter_party_regime_root - account_holder_payment_account_root - account_holder_payment_account_regime_root - counter_party_payment_account_root - counter_party_payment_account_regime_root type: string x-struct: x-validate: ledger_account_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_id: format: uuid type: string x-struct: x-validate: linked_ledger_accounts: description: Read-only edge list — every related LedgerAccount (ancestor or descendant), with the edge `type` indicating direction. Populated automatically by a database trigger on LedgerAccount insert; never written by application code. items: $ref: '#/components/schemas/LinkedLedgerAccountResponse' readOnly: true type: array x-struct: x-validate: payment_account_id: description: PaymentAccount this account belongs to (NULL on master roots). format: uuid nullable: true type: string x-struct: x-validate: regime: description: Generic regime discriminator (regulatory regime, fraud regime, …). Regime leaves carry the real regime name; aggregation roots carry the sentinel "root". type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - ledger_id - currency - regime title: LedgerAccountResponse type: object x-order: - id - account_holder_id - ledger_id - currency - regime - status - balance - ledger_account_number - payment_account_id - counterparty_id - la_type - linked_ledger_accounts - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountResponse x-validate: CounterpartyListResponse: description: Paginated list of counterparties properties: data: description: List of counterparties items: $ref: '#/components/schemas/CounterpartyResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: CounterpartyListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyListResponse x-validate: NormalizationRulesResponse: description: Data quality normalization rules used for account holder screening example: entity_types: - llc - inc - corp - ltd - llp - co - company suffixes: - jr - sr - ii - iii - iv - v - esq titles: - mr - mrs - ms - dr - prof - sir - madam - miss properties: entity_types: description: Company entity types to remove during normalization (e.g., LLC, Inc, Corp) example: - llc - inc - corp - ltd - llp items: type: string x-struct: x-validate: type: array x-struct: x-validate: suffixes: description: Name suffixes to standardize during normalization (e.g., Jr., Sr., III) example: - jr - sr - ii - iii - iv - esq items: type: string x-struct: x-validate: type: array x-struct: x-validate: titles: description: Name titles to strip during normalization (e.g., Mr., Mrs., Dr.) example: - mr - mrs - ms - dr - prof items: type: string x-struct: x-validate: type: array x-struct: x-validate: required: - titles - suffixes - entity_types title: NormalizationRulesResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.NormalizationRulesResponse x-validate: PaymentAccountListResponse: description: Paginated list of payment_accounts properties: data: description: List of payment_accounts items: $ref: '#/components/schemas/PaymentAccountResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: PaymentAccountListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountListResponse x-validate: ComplianceScreeningResponse: description: ISO 20022 compliance screening record (auth:018 / camt:998). One row per entity per screening run. scope controls the payment lifecycle gate; screening_type narrows the check performed. Child sanctions_matches and blocklist_matches carry per-hit detail and reviewer decisions. example: aml_control_count: 0 aml_high_risk_country: '' screening_type: sanctions compliance_screening_number: '' sanctions_screening_date: 2020-04-20T16:20:00Z scope: account_holder match_count: 0 false_positive_qualifier: none screening_status: pending manual_review_required: false aml_control_flag: false screening_score: 0 screened_at: 2020-04-20T16:20:00Z sanctions_screening_status: cleared legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 screening_rules: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 screened_entity_type: individual id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 pep_indicator: false pep_list_name: '' updated_at: 2020-04-20T16:20:00Z reviewed_at: 2020-04-20T16:20:00Z aml_geographic_risk_flag: false review_notes: '' sanctions_matches: - aml_risk_score: 0 screened_entity_name: '' inserted_at: 2020-04-20T16:20:00Z blocklist_matches: - escalation_level: 0 properties: aml_control_count: nullable: true type: integer x-struct: x-validate: aml_high_risk_country: nullable: true type: string x-struct: x-validate: screening_type: enum: - sanctions - pep - aml - adverse_media type: string x-struct: x-validate: compliance_screening_number: nullable: true type: string x-struct: x-validate: sanctions_screening_date: format: date-time nullable: true type: string x-struct: x-validate: scope: enum: - account_holder - beneficial_owner - counterparty - payment_account - transaction type: string x-struct: x-validate: match_count: nullable: true type: integer x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: screening_status: enum: - pending - pass - potential_match - blocked - escalated type: string x-struct: x-validate: manual_review_required: type: boolean x-struct: x-validate: aml_control_flag: nullable: true type: boolean x-struct: x-validate: screening_score: format: decimal nullable: true type: number x-struct: x-validate: screened_at: format: date-time nullable: true type: string x-struct: x-validate: sanctions_screening_status: enum: - cleared - pending - match - failed nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: screening_rules: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: screened_entity_type: enum: - individual - company - crypto_address - payment_account type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: payment_account_id: format: uuid nullable: true type: string x-struct: x-validate: pep_indicator: nullable: true type: boolean x-struct: x-validate: pep_list_name: nullable: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: aml_geographic_risk_flag: nullable: true type: boolean x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: sanctions_matches: items: $ref: '#/components/schemas/SanctionsMatchResponse' readOnly: true type: array x-struct: x-validate: aml_risk_score: format: decimal nullable: true type: number x-struct: x-validate: screened_entity_name: type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: blocklist_matches: items: $ref: '#/components/schemas/BlocklistMatchResponse' readOnly: true type: array x-struct: x-validate: escalation_level: nullable: true type: integer x-struct: x-validate: readOnly: true required: - scope - screening_type - screening_status - screened_entity_type - screened_entity_name title: ComplianceScreeningResponse type: object x-order: - id - scope - screening_type - screening_status - screening_score - screened_entity_type - screened_entity_name - match_count - screened_at - screening_rules - sanctions_screening_status - sanctions_screening_date - pep_indicator - pep_list_name - aml_risk_score - aml_control_flag - aml_control_count - aml_geographic_risk_flag - aml_high_risk_country - false_positive_qualifier - manual_review_required - reviewed_at - reviewed_by_user_id - review_notes - escalation_level - compliance_screening_number - legal_entity_id - payment_account_id - tenant_id - inserted_at - updated_at - sanctions_matches - blocklist_matches x-struct: Elixir.AtomicFi.OpenApiSchema.ComplianceScreeningResponse x-validate: LedgerEntryRequest: description: Debit/credit line item (ISO 20022 CdtDbtInd) on a leaf LedgerAccount. Created in balanced pairs (Σ debits = Σ credits). The propagate trigger rolls the amount + the entry's control limits up the ledger-account ancestor chain; a breached limit CHECK persists the entry :voided with the rejected_* details. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 currency: '' entry_date: 2020-04-20 entry_type: credit external_entry_id: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 limits_at_entry: - status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (e.g. cents for USD). Must be >= 0. type: integer x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from LedgerAccount → Ledger. type: string x-struct: x-validate: entry_date: description: ISO 20022 ValDt — value/settlement date format: date nullable: true type: string x-struct: x-validate: entry_type: enum: - credit - debit type: string x-struct: x-validate: external_entry_id: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid type: string x-struct: x-validate: limits_at_entry: description: Control limits (rule engine output) for this entry's leaf account. The trigger fans these into ledger_account_balances.last_*_limit on every ancestor. items: $ref: '#/components/schemas/ControlLimitRequest' nullable: true type: array writeOnly: true x-struct: x-validate: status: enum: - pending - posted - reversed - voided nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_account_id - currency - amount - entry_type title: LedgerEntryRequest type: object writeOnly: true x-order: - account_holder_id - ledger_account_id - currency - amount - entry_type - status - entry_date - external_entry_id - limits_at_entry - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerEntryRequest x-validate: DocumentListResponse: description: Paginated list of documents properties: data: description: List of documents items: $ref: '#/components/schemas/DocumentResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: DocumentListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.DocumentListResponse x-validate: AccountActivitySnapshotRequest: description: Account activity snapshot — periodic summary of debit/credit activity for an AccountHolder. Maps to ISO 20022 camt:052 (intraday account report) and camt:053 (account statement). AML fields (flagged_for_review, review_reason, sar_reference) support FinCEN SAR filing under 31 CFR §1020.320. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 closing_balance: 0 currency: '' external_reference: '' flagged_for_review: false ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 opening_balance: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 period_end: 2020-04-20T16:20:00Z period_start: 2020-04-20T16:20:00Z review_reason: '' sar_reference: '' snapshot_type: intraday status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_credit_count: 0 total_debit_amount: 0 total_debit_count: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: closing_balance: description: Balance at period end in minor currency units (camt:053 ClosingBooked) nullable: true type: integer x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: external_reference: description: Caller-supplied idempotency key (unique per tenant when set) nullable: true type: string x-struct: x-validate: flagged_for_review: description: AML review flag — true when activity patterns exceed FinCEN AML thresholds (31 CFR §1020.320 SAR requirements) type: boolean x-struct: x-validate: ledger_account_id: description: LedgerAccount scoping this snapshot (chart-of-accounts view) format: uuid nullable: true type: string x-struct: x-validate: opening_balance: description: Balance at period start in minor currency units (camt:053 OpeningBooked) nullable: true type: integer x-struct: x-validate: payment_account_id: description: PaymentAccount scoping this snapshot (camt:052/053 ) format: uuid nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: review_reason: description: Human-readable description of why this snapshot was flagged for AML review nullable: true type: string x-struct: x-validate: sar_reference: description: SAR (Suspicious Activity Report) filing reference (FinCEN SAR form 111) nullable: true type: string x-struct: x-validate: snapshot_type: description: Reporting period type — intraday maps to camt:052 (on-demand report); daily/weekly/monthly map to camt:053 (periodic statement) enum: - intraday - daily - weekly - monthly type: string x-struct: x-validate: status: description: Snapshot lifecycle status — pending (queued), computed (aggregates ready), published (sent to downstream / regulatory reporting) enum: - pending - computed - published nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount in minor currency units (camt:052/053 TtlCdtNtries Amt) type: integer x-struct: x-validate: total_credit_count: description: Number of credit entries in the period (camt:052/053 CdtNb) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount in minor currency units (camt:052/053 TtlDbtNtries Amt) type: integer x-struct: x-validate: total_debit_count: description: Number of debit entries in the period (camt:052/053 DbtNb) type: integer x-struct: x-validate: transaction_count: description: Total number of transactions (debit + credit) in the period type: integer x-struct: x-validate: required: - snapshot_type - period_start - period_end - account_holder_id - tenant_id title: AccountActivitySnapshotRequest type: object writeOnly: true x-order: - snapshot_type - period_start - period_end - opening_balance - closing_balance - currency - total_debit_count - total_credit_count - total_debit_amount - total_credit_amount - transaction_count - status - flagged_for_review - review_reason - sar_reference - external_reference - account_holder_id - payment_account_id - ledger_account_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotRequest x-validate: PaginationMeta: description: Pagination metadata for list responses example: page: 1 page_size: 50 total_count: 125 total_pages: 3 properties: page: description: Current page number (1-indexed) example: 1 type: integer x-struct: x-validate: page_size: description: Number of items per page example: 50 type: integer x-struct: x-validate: total_count: description: Total number of items across all pages example: 125 type: integer x-struct: x-validate: total_pages: description: Total number of pages example: 3 type: integer x-struct: x-validate: required: - page - page_size - total_count - total_pages title: PaginationMeta type: object x-struct: Elixir.AtomicFi.OpenApiSchema.PaginationMeta x-validate: CounterpartyResponse: description: External payer/payee (ISO 20022 /) that an AccountHolder transacts with. All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object on POST. The LE link is immutable post-create (LE carries the FK back, not CP). To replace LE PII, use `PUT /api/counterparties/:id/legal-entity`. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owners: - counterparty_number: '' enabled_regimes: - "" external_id: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z legal_entity: status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owners: items: $ref: '#/components/schemas/BeneficialOwnerResponse' readOnly: true type: array x-struct: x-validate: counterparty_number: readOnly: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityResponse' status: enum: - active - suspended - blocked type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - status title: CounterpartyResponse type: object x-order: - id - account_holder_id - legal_entity - status - external_id - counterparty_number - enabled_regimes - tenant_id - inserted_at - updated_at - beneficial_owners x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyResponse x-validate: LegalEntityAddressResponse: description: Address record for a legal entity example: address_types: - business country: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 line1: '' line2: '' locality: '' postal_code: '' primary: false region: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: address_types: items: enum: - business - mailing - residential - po_box - other type: string x-struct: x-validate: type: array x-struct: x-validate: country: nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: legal_entity_id: format: uuid readOnly: true type: string x-struct: x-validate: line1: nullable: true type: string x-struct: x-validate: line2: nullable: true type: string x-struct: x-validate: locality: nullable: true type: string x-struct: x-validate: postal_code: nullable: true type: string x-struct: x-validate: primary: nullable: true type: boolean x-struct: x-validate: region: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - address_types title: LegalEntityAddressResponse type: object x-order: - id - legal_entity_id - address_types - primary - line1 - line2 - locality - region - postal_code - country - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityAddressResponse x-validate: LegalEntityChangeEventListResponse: description: Paginated list of legal_entity_change_events properties: data: description: List of legal_entity_change_events items: $ref: '#/components/schemas/LegalEntityChangeEventResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: LegalEntityChangeEventListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventListResponse x-validate: ApiKeyResponse: description: Api key schema. `raw_key` is populated ONCE on create — store it securely client-side, it cannot be retrieved later. example: id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z last_used_at: 2020-04-20T16:20:00Z name: '' raw_key: '' role_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: last_used_at: format: date-time nullable: true readOnly: true type: string x-struct: x-validate: name: type: string x-struct: x-validate: raw_key: nullable: true readOnly: true type: string x-struct: x-validate: role_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - name - tenant_id - role_id title: ApiKeyResponse type: object x-order: - id - name - raw_key - last_used_at - tenant_id - role_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.ApiKeyResponse x-validate: LegalEntityResponse: description: Shared identity record for individuals and businesses per ISO 20022 acmt:007 + FATF CDD example: addresses: - business_name: '' citizenship_country: '' date_formed: 2020-04-20 date_of_birth: 2020-04-20 doing_business_as_names: - "" first_name: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 identifications: - inserted_at: 2020-04-20T16:20:00Z last_name: '' latest_change_event_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_number: '' legal_entity_type: individual legal_structure: corporation middle_name: '' phone_numbers: - politically_exposed_person: false preferred_name: '' prefix: '' subject_type: account_holder suffix: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z website: '' properties: addresses: items: $ref: '#/components/schemas/LegalEntityAddressRequest' type: array x-struct: x-validate: business_name: nullable: true type: string x-struct: x-validate: citizenship_country: nullable: true type: string x-struct: x-validate: date_formed: format: date nullable: true type: string x-struct: x-validate: date_of_birth: format: date nullable: true type: string x-struct: x-validate: doing_business_as_names: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: first_name: nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: identifications: items: $ref: '#/components/schemas/LegalEntityIdentificationRequest' type: array x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: last_name: nullable: true type: string x-struct: x-validate: latest_change_event_id: description: UUID of the most recent LegalEntityChangeEvent for this entity. Maintained by DB trigger after each change event insert — never written directly. format: uuid nullable: true readOnly: true type: string x-struct: x-validate: legal_entity_number: readOnly: true type: string x-struct: x-validate: legal_entity_type: enum: - individual - business type: string x-struct: x-validate: legal_structure: enum: - corporation - llc - non_profit - partnership - sole_proprietorship - trust - government nullable: true type: string x-struct: x-validate: middle_name: nullable: true type: string x-struct: x-validate: phone_numbers: items: $ref: '#/components/schemas/LegalEntityPhoneNumberRequest' type: array x-struct: x-validate: politically_exposed_person: nullable: true type: boolean x-struct: x-validate: preferred_name: nullable: true type: string x-struct: x-validate: prefix: nullable: true type: string x-struct: x-validate: subject_type: enum: - account_holder - counterparty - account_holder_beneficial_owner - counterparty_beneficial_owner nullable: true readOnly: true type: string x-struct: x-validate: suffix: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: website: format: uri nullable: true type: string x-struct: x-validate: readOnly: true required: - legal_entity_type - tenant_id title: LegalEntityResponse type: object x-order: - id - legal_entity_type - legal_structure - subject_type - business_name - doing_business_as_names - date_formed - website - first_name - middle_name - last_name - prefix - suffix - preferred_name - date_of_birth - citizenship_country - politically_exposed_person - addresses - phone_numbers - identifications - tenant_id - legal_entity_number - latest_change_event_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityResponse x-validate: PaymentAccountResponse: description: 'Payment account — one row per payment instrument linked to an AccountHolder (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer rule compliance. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing.' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 account_number: '' account_type: bank_account bank_name: '' card_pan: '' counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' enabled_regimes: - "" external_id: '' iban: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_number: '' routing_number: '' status: active swift_bic: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z wallet_address: '' wallet_chain: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: account_number: description: Bank account number (PCI-DSS sensitive — tokenise before storing) nullable: true type: string x-struct: x-validate: account_type: enum: - bank_account - card - wallet - crypto_wallet type: string x-struct: x-validate: bank_name: description: Name of the account's bank nullable: true type: string x-struct: x-validate: card_pan: description: Card PAN last-4 or token (PCI-DSS — never store raw PAN) nullable: true type: string x-struct: x-validate: counterparty_id: format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: iban: description: International Bank Account Number (IBAN) nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: ledger_account_id: format: uuid nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: payment_account_number: description: Opaque internal payment account number nullable: true type: string x-struct: x-validate: routing_number: description: Bank routing / sort code nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - blocked nullable: true type: string x-struct: x-validate: swift_bic: description: SWIFT/BIC code of the account's bank nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: wallet_address: description: On-chain wallet address (the actual identifier funds settle to). Set together with wallet_chain when account_type = :crypto_wallet. nullable: true type: string x-struct: x-validate: wallet_chain: description: Blockchain / asset ticker the wallet_address lives on (e.g. "BTC", "ETH", "TRON"). Disambiguates same-format addresses across chains. nullable: true type: string x-struct: x-validate: readOnly: true required: - account_type - account_holder_id - tenant_id title: PaymentAccountResponse type: object x-order: - id - account_type - status - currency - account_number - routing_number - iban - swift_bic - bank_name - card_pan - wallet_address - wallet_chain - payment_account_number - external_id - account_holder_id - legal_entity_id - counterparty_id - ledger_account_id - enabled_regimes - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountResponse x-validate: PartyActivitySnapshotRequest: description: Party-level AML monitoring snapshot for an AccountHolder. Captures KYC/risk transitions, screening activity, transaction shape, and SAR candidacy across a reporting window (FATF Rec 10 ongoing CDD · FinCEN 31 CFR §1020.320 SAR). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 high_risk_transaction_count: 0 kyc_status_at_end: not_started kyc_status_at_start: not_started notes: '' period_end: 2020-04-20 period_start: 2020-04-20 period_type: daily risk_level_at_end: low risk_level_at_start: low sar_indicator: false screening_hits: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_debit_amount: 0 total_screenings: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: high_risk_transaction_count: description: Transactions exceeding risk thresholds type: integer x-struct: x-validate: kyc_status_at_end: description: AccountHolder.kyc_status at period close enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: kyc_status_at_start: description: AccountHolder.kyc_status at period open enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_type: description: Reporting period cadence — daily/weekly/monthly snapshots feed ongoing CDD (FATF Rec 10); quarterly snapshots support SAR narrative evidence (FinCEN 31 CFR §1020.320). enum: - daily - weekly - monthly - quarterly type: string x-struct: x-validate: risk_level_at_end: description: AccountHolder.risk_level at period close enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: risk_level_at_start: description: AccountHolder.risk_level at period open enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: sar_indicator: description: SAR (Suspicious Activity Report) filing consideration flag type: boolean x-struct: x-validate: screening_hits: description: Potential/confirmed screening matches type: integer x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount (minor currency units) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount (minor currency units) type: integer x-struct: x-validate: total_screenings: description: Compliance screenings run in the period type: integer x-struct: x-validate: transaction_count: description: Transactions in the period type: integer x-struct: x-validate: required: - account_holder_id - period_type - period_start - period_end - tenant_id title: PartyActivitySnapshotRequest type: object writeOnly: true x-order: - account_holder_id - period_type - period_start - period_end - kyc_status_at_start - kyc_status_at_end - risk_level_at_start - risk_level_at_end - total_screenings - screening_hits - transaction_count - total_debit_amount - total_credit_amount - high_risk_transaction_count - sar_indicator - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotRequest x-validate: TenantRequest: description: Tenant schema for multi-tenancy Request example: enabled_regimes: - "" id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' slug: '' status: active tenant_type: platform updated_at: 2020-04-20T16:20:00Z properties: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: id: format: uuid type: string x-struct: x-validate: inserted_at: format: date-time type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: slug: nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - inactive type: string x-struct: x-validate: tenant_type: enum: - platform - standard type: string x-struct: x-validate: updated_at: format: date-time type: string x-struct: x-validate: required: - name - tenant_type title: TenantRequest type: object writeOnly: true x-order: - id - name - slug - status - tenant_type - metadata - enabled_regimes - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.TenantRequest x-validate: WatchmanContactRequest: description: Normalized Watchman contact block Request example: emails: - "" phones: - "" websites: - "" properties: emails: items: type: string x-struct: x-validate: type: array x-struct: x-validate: phones: items: type: string x-struct: x-validate: type: array x-struct: x-validate: websites: items: type: string x-struct: x-validate: type: array x-struct: x-validate: title: WatchmanContactRequest type: object writeOnly: true x-order: - emails - phones - websites x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanContactRequest x-validate: WatchmanBusinessResponse: description: Normalized Watchman business block example: dissolved_date: '' incorporation_date: '' name: '' registration_number: '' properties: dissolved_date: nullable: true type: string x-struct: x-validate: incorporation_date: nullable: true type: string x-struct: x-validate: name: nullable: true type: string x-struct: x-validate: registration_number: nullable: true type: string x-struct: x-validate: readOnly: true title: WatchmanBusinessResponse type: object x-order: - name - registration_number - incorporation_date - dissolved_date x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanBusinessResponse x-validate: PartyActivitySnapshotResponse: description: Party-level AML monitoring snapshot for an AccountHolder. Captures KYC/risk transitions, screening activity, transaction shape, and SAR candidacy across a reporting window (FATF Rec 10 ongoing CDD · FinCEN 31 CFR §1020.320 SAR). example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 high_risk_transaction_count: 0 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z kyc_status_at_end: not_started kyc_status_at_start: not_started notes: '' period_end: 2020-04-20 period_start: 2020-04-20 period_type: daily risk_level_at_end: low risk_level_at_start: low sar_indicator: false screening_hits: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_debit_amount: 0 total_screenings: 0 transaction_count: 0 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: high_risk_transaction_count: description: Transactions exceeding risk thresholds type: integer x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: kyc_status_at_end: description: AccountHolder.kyc_status at period close enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: kyc_status_at_start: description: AccountHolder.kyc_status at period open enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_type: description: Reporting period cadence — daily/weekly/monthly snapshots feed ongoing CDD (FATF Rec 10); quarterly snapshots support SAR narrative evidence (FinCEN 31 CFR §1020.320). enum: - daily - weekly - monthly - quarterly type: string x-struct: x-validate: risk_level_at_end: description: AccountHolder.risk_level at period close enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: risk_level_at_start: description: AccountHolder.risk_level at period open enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: sar_indicator: description: SAR (Suspicious Activity Report) filing consideration flag type: boolean x-struct: x-validate: screening_hits: description: Potential/confirmed screening matches type: integer x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount (minor currency units) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount (minor currency units) type: integer x-struct: x-validate: total_screenings: description: Compliance screenings run in the period type: integer x-struct: x-validate: transaction_count: description: Transactions in the period type: integer x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - period_type - period_start - period_end - tenant_id title: PartyActivitySnapshotResponse type: object x-order: - id - account_holder_id - period_type - period_start - period_end - kyc_status_at_start - kyc_status_at_end - risk_level_at_start - risk_level_at_end - total_screenings - screening_hits - transaction_count - total_debit_amount - total_credit_amount - high_risk_transaction_count - sar_indicator - notes - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotResponse x-validate: LedgerRequest: description: ISO 20022 camt:052/camt:053 chart-of-accounts container — one per AccountHolder per currency. Balance is derived on-read by summing child LedgerAccount.balance values. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' ledger_number: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code (e.g. USD). Authoritative for the entire ledger hierarchy. type: string x-struct: x-validate: ledger_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - currency title: LedgerRequest type: object writeOnly: true x-order: - account_holder_id - currency - status - ledger_number - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerRequest x-validate: RoleResponse: description: Role schema example: description: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: description: type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - name - description - tenant_id title: RoleResponse type: object x-order: - id - name - description - metadata - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.RoleResponse x-validate: AccountActivitySnapshotListResponse: description: Paginated list of account_activity_snapshots properties: data: description: List of account_activity_snapshots items: $ref: '#/components/schemas/AccountActivitySnapshotResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: AccountActivitySnapshotListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotListResponse x-validate: BlocklistMatchResponse: description: One internal blocklist hit. false_positive_qualifier persists reviewer decisions across re-screenings. blocklist_updated_at lets reviewers re-evaluate overrides after list updates. example: blocklist_updated_at: 2020-04-20T16:20:00Z compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 false_positive_qualifier: none id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z match_type: exact matched_term: '' reason: '' review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 scope: first_name tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: blocklist_updated_at: format: date-time nullable: true type: string x-struct: x-validate: compliance_screening_id: format: uuid readOnly: true type: string x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: match_type: enum: - exact - regex type: string x-struct: x-validate: matched_term: type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - matched_term - match_type - scope title: BlocklistMatchResponse type: object x-order: - id - compliance_screening_id - matched_term - match_type - scope - reason - blocklist_updated_at - false_positive_qualifier - review_notes - reviewed_by_user_id - reviewed_at - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistMatchResponse x-validate: WatchmanContactResponse: description: Normalized Watchman contact block example: emails: - "" phones: - "" websites: - "" properties: emails: items: type: string x-struct: x-validate: type: array x-struct: x-validate: phones: items: type: string x-struct: x-validate: type: array x-struct: x-validate: websites: items: type: string x-struct: x-validate: type: array x-struct: x-validate: readOnly: true title: WatchmanContactResponse type: object x-order: - emails - phones - websites x-struct: Elixir.AtomicFi.OpenApiSchema.WatchmanContactResponse x-validate: LegalEntityChangeEventResponse: description: Audit log of non-financial identity lifecycle changes to a LegalEntity. Maps to ISO 20022 acmt:006 (AccountModificationInstruction) and acmt:002 (AccountDetailsConfirmation). Auto-created by update_legal_entity via prepare_changes — not returned in the update response (requires a separate GET /legal-entity-change-events). Primary AML signal source for account takeover detection. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 acmt_confirmation_id: '' acmt_instruction_id: '' beneficial_owner_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 change_channel: web changes: {} event_status: pending event_type: address_change id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 previous_state: {} tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: description: AccountHolder context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: acmt_confirmation_id: description: acmt:002 MsgId — confirmation message reference, populated once confirmed nullable: true type: string x-struct: x-validate: acmt_instruction_id: description: acmt:006 MsgId — upsert deduplication key. Unique per tenant when set (sparse unique index) nullable: true type: string x-struct: x-validate: beneficial_owner_id: description: BeneficialOwner context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: change_channel: description: Channel through which the modification request was received enum: - web - mobile - branch - api - phone_banking type: string x-struct: x-validate: changes: description: 'JSONB diff of changed fields: keys are field names, values are [previous_value, new_value]. System-generated from Ecto changeset on update_legal_entity — not user-supplied.' nullable: true readOnly: true type: object x-struct: x-validate: event_status: description: Lifecycle status — pending (change requested), confirmed (verified and applied), rejected (denied by compliance / KYC check), recorded (automatically set by DB trigger for system-generated events) enum: - pending - confirmed - rejected - recorded nullable: true type: string x-struct: x-validate: event_type: description: 'Type of identity change — maps to acmt:006 MdcnCd (Modification Code). Primary AML signals: phone_change (SIM swap), address_change (address control), beneficiary_added / authorised_signer_change (pre-transfer grooming)' enum: - address_change - phone_change - email_change - beneficiary_added - beneficiary_removed - beneficiary_modified - account_inquiry - contact_info_change - authorised_signer_change type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: previous_state: description: Full JSONB snapshot of the LegalEntity state before this change was applied. System-generated on update_legal_entity — not user-supplied. nullable: true readOnly: true type: object x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - event_type - change_channel - legal_entity_id - tenant_id title: LegalEntityChangeEventResponse type: object x-order: - id - event_type - change_channel - event_status - acmt_instruction_id - acmt_confirmation_id - changes - previous_state - legal_entity_id - account_holder_id - beneficial_owner_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventResponse x-validate: ContactRequest: description: Contact information (Watchman format) Request example: emailAddresses: - "" faxNumbers: - "" phoneNumbers: - "" websites: - "" properties: emailAddresses: items: type: string x-struct: x-validate: type: array x-struct: x-validate: faxNumbers: items: type: string x-struct: x-validate: type: array x-struct: x-validate: phoneNumbers: items: type: string x-struct: x-validate: type: array x-struct: x-validate: websites: items: type: string x-struct: x-validate: type: array x-struct: x-validate: title: ContactRequest type: object writeOnly: true x-order: - emailAddresses - faxNumbers - phoneNumbers - websites x-struct: Elixir.AtomicFi.OpenApiSchema.ContactRequest x-validate: LegalEntityIdentificationResponse: description: Identity document for a legal entity per FATF CDD requirements. Unique per (legal_entity_id, id_type). example: expiration_date: 2020-04-20 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 id_number: '' id_type: us_ssn inserted_at: 2020-04-20T16:20:00Z issuing_country: '' issuing_region: '' legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z uri: '' properties: expiration_date: format: date nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: id_number: nullable: true type: string x-struct: x-validate: id_type: enum: - us_ssn - us_ein - us_itin - passport - driver_license - national_id - lei - tax_id type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: issuing_country: nullable: true type: string x-struct: x-validate: issuing_region: nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid readOnly: true type: string x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: uri: nullable: true type: string x-struct: x-validate: readOnly: true required: - id_type title: LegalEntityIdentificationResponse type: object x-order: - id - legal_entity_id - id_type - uri - id_number - issuing_country - issuing_region - expiration_date - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityIdentificationResponse x-validate: LedgerAccountBalanceResponse: description: Daily balance snapshot for a LedgerAccount. Created and updated entirely by the ledger_entry_propagate_to_balances trigger. Each row carries day/week/month/year cumulative totals and last known risk engine limits. Control limits are enforced via DB CHECK constraints on last_*_limit columns. example: balance_date: 2020-04-20 daily_credit: 0 daily_debit: 0 id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z iso_week: 0 last_daily_credit_limit: 0 last_daily_debit_limit: 0 last_monthly_credit_limit: 0 last_monthly_debit_limit: 0 last_weekly_credit_limit: 0 last_weekly_debit_limit: 0 last_yearly_credit_limit: 0 last_yearly_debit_limit: 0 ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 month: 0 monthly_credit: 0 monthly_debit: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z weekly_credit: 0 weekly_debit: 0 year: 0 yearly_credit: 0 yearly_debit: 0 properties: balance_date: description: Calendar date for this snapshot format: date readOnly: true type: string x-struct: x-validate: daily_credit: description: Total credits on this calendar day (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: daily_debit: description: Total debits on this calendar day (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: iso_week: description: ISO week number (1–53) readOnly: true type: integer x-struct: x-validate: last_daily_credit_limit: description: Last known daily credit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_daily_debit_limit: description: Last known daily debit limit from risk engine (minor currency units). NULL = unconstrained. Enforced by DB CHECK constraint. Trigger-maintained. nullable: true readOnly: true type: integer x-struct: x-validate: last_monthly_credit_limit: description: Last known monthly credit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_monthly_debit_limit: description: Last known monthly debit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_weekly_credit_limit: description: Last known weekly credit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_weekly_debit_limit: description: Last known weekly debit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_yearly_credit_limit: description: Last known yearly credit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: last_yearly_debit_limit: description: Last known yearly debit limit from risk engine. NULL = unconstrained. nullable: true readOnly: true type: integer x-struct: x-validate: ledger_account_id: format: uuid type: string x-struct: x-validate: month: description: Calendar month (1–12) readOnly: true type: integer x-struct: x-validate: monthly_credit: description: Month-to-date cumulative credits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: monthly_debit: description: Month-to-date cumulative debits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: tenant_id: format: uuid readOnly: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: weekly_credit: description: Week-to-date cumulative credits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: weekly_debit: description: Week-to-date cumulative debits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: year: description: Calendar year readOnly: true type: integer x-struct: x-validate: yearly_credit: description: Year-to-date cumulative credits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: yearly_debit: description: Year-to-date cumulative debits (minor currency units). Trigger-maintained. readOnly: true type: integer x-struct: x-validate: readOnly: true required: - ledger_account_id title: LedgerAccountBalanceResponse type: object x-order: - id - ledger_account_id - balance_date - iso_week - month - year - daily_debit - daily_credit - weekly_debit - weekly_credit - monthly_debit - monthly_credit - yearly_debit - yearly_credit - last_daily_debit_limit - last_daily_credit_limit - last_weekly_debit_limit - last_weekly_credit_limit - last_monthly_debit_limit - last_monthly_credit_limit - last_yearly_debit_limit - last_yearly_credit_limit - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountBalanceResponse x-validate: ComplianceScreeningRequest: description: ISO 20022 compliance screening record (auth:018 / camt:998). One row per entity per screening run. scope controls the payment lifecycle gate; screening_type narrows the check performed. Child sanctions_matches and blocklist_matches carry per-hit detail and reviewer decisions. Request example: aml_control_count: 0 aml_control_flag: false aml_geographic_risk_flag: false aml_high_risk_country: '' aml_risk_score: 0 compliance_screening_number: '' escalation_level: 0 false_positive_qualifier: none legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 manual_review_required: false match_count: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 pep_indicator: false pep_list_name: '' review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 sanctions_screening_date: 2020-04-20T16:20:00Z sanctions_screening_status: cleared scope: account_holder screened_at: 2020-04-20T16:20:00Z screened_entity_name: '' screened_entity_type: individual screening_rules: '' screening_score: 0 screening_status: pending screening_type: sanctions properties: aml_control_count: nullable: true type: integer x-struct: x-validate: aml_control_flag: nullable: true type: boolean x-struct: x-validate: aml_geographic_risk_flag: nullable: true type: boolean x-struct: x-validate: aml_high_risk_country: nullable: true type: string x-struct: x-validate: aml_risk_score: format: decimal nullable: true type: number x-struct: x-validate: compliance_screening_number: nullable: true type: string x-struct: x-validate: escalation_level: nullable: true type: integer x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: manual_review_required: type: boolean x-struct: x-validate: match_count: nullable: true type: integer x-struct: x-validate: payment_account_id: format: uuid nullable: true type: string x-struct: x-validate: pep_indicator: nullable: true type: boolean x-struct: x-validate: pep_list_name: nullable: true type: string x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: sanctions_screening_date: format: date-time nullable: true type: string x-struct: x-validate: sanctions_screening_status: enum: - cleared - pending - match - failed nullable: true type: string x-struct: x-validate: scope: enum: - account_holder - beneficial_owner - counterparty - payment_account - transaction type: string x-struct: x-validate: screened_at: format: date-time nullable: true type: string x-struct: x-validate: screened_entity_name: type: string x-struct: x-validate: screened_entity_type: enum: - individual - company - crypto_address - payment_account type: string x-struct: x-validate: screening_rules: nullable: true type: string x-struct: x-validate: screening_score: format: decimal nullable: true type: number x-struct: x-validate: screening_status: enum: - pending - pass - potential_match - blocked - escalated type: string x-struct: x-validate: screening_type: enum: - sanctions - pep - aml - adverse_media type: string x-struct: x-validate: required: - scope - screening_type - screening_status - screened_entity_type - screened_entity_name title: ComplianceScreeningRequest type: object writeOnly: true x-order: - scope - screening_type - screening_status - screening_score - screened_entity_type - screened_entity_name - match_count - screened_at - screening_rules - sanctions_screening_status - sanctions_screening_date - pep_indicator - pep_list_name - aml_risk_score - aml_control_flag - aml_control_count - aml_geographic_risk_flag - aml_high_risk_country - false_positive_qualifier - manual_review_required - reviewed_at - reviewed_by_user_id - review_notes - escalation_level - compliance_screening_number - legal_entity_id - payment_account_id x-struct: Elixir.AtomicFi.OpenApiSchema.ComplianceScreeningRequest x-validate: LegalEntityChangeEventRequest: description: Audit log of non-financial identity lifecycle changes to a LegalEntity. Maps to ISO 20022 acmt:006 (AccountModificationInstruction) and acmt:002 (AccountDetailsConfirmation). Auto-created by update_legal_entity via prepare_changes — not returned in the update response (requires a separate GET /legal-entity-change-events). Primary AML signal source for account takeover detection. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 acmt_confirmation_id: '' acmt_instruction_id: '' beneficial_owner_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 change_channel: web event_status: pending event_type: address_change legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: description: AccountHolder context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: acmt_confirmation_id: description: acmt:002 MsgId — confirmation message reference, populated once confirmed nullable: true type: string x-struct: x-validate: acmt_instruction_id: description: acmt:006 MsgId — upsert deduplication key. Unique per tenant when set (sparse unique index) nullable: true type: string x-struct: x-validate: beneficial_owner_id: description: BeneficialOwner context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: change_channel: description: Channel through which the modification request was received enum: - web - mobile - branch - api - phone_banking type: string x-struct: x-validate: event_status: description: Lifecycle status — pending (change requested), confirmed (verified and applied), rejected (denied by compliance / KYC check), recorded (automatically set by DB trigger for system-generated events) enum: - pending - confirmed - rejected - recorded nullable: true type: string x-struct: x-validate: event_type: description: 'Type of identity change — maps to acmt:006 MdcnCd (Modification Code). Primary AML signals: phone_change (SIM swap), address_change (address control), beneficiary_added / authorised_signer_change (pre-transfer grooming)' enum: - address_change - phone_change - email_change - beneficiary_added - beneficiary_removed - beneficiary_modified - account_inquiry - contact_info_change - authorised_signer_change type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - event_type - change_channel - legal_entity_id - tenant_id title: LegalEntityChangeEventRequest type: object writeOnly: true x-order: - event_type - change_channel - event_status - acmt_instruction_id - acmt_confirmation_id - legal_entity_id - account_holder_id - beneficial_owner_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventRequest x-validate: TransactionResponse: description: 'Payment transaction — one row per payment instruction or transfer event. Covers pain:001 (initiation), pacs:008 (interbank), pacs:002 (status), pacs:004 (return), camt:054 (booking notification). FATF Rec 16: debtor/creditor payment accounts must be verified before settlement.' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' debtor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 debtor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 end_to_end_id: '' external_id: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z instruction_id: '' ledger_entry_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 rejected_code: '' rejected_direction: debit rejected_ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 rejected_period: daily rejected_rule: '' requested_execution_date: 2020-04-20 settlement_date: 2020-04-20 status: pending status_reason_code: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 transaction_number: '' transaction_type: credit_transfer uetr: '' updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (cents) — always positive type: integer x-struct: x-validate: compliance_screening_id: description: ComplianceScreening result for this transaction (auth:018 / camt:998) format: uuid nullable: true type: string x-struct: x-validate: creditor_counterparty_id: description: Creditor (payee) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: creditor_payment_account_id: description: Creditor (payee) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) type: string x-struct: x-validate: debtor_counterparty_id: description: Debtor (payer) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: debtor_payment_account_id: description: Debtor (payer) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: end_to_end_id: description: pain:001 EndToEndId — set by originating party, immutable once set nullable: true type: string x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: instruction_id: description: pain:001 TxId — instruction ID from the payment initiation message nullable: true type: string x-struct: x-validate: ledger_entry_id: description: LedgerEntry created by this transaction (camt:052/053 Ntry) format: uuid nullable: true type: string x-struct: x-validate: rejected_code: description: e.g. LIMIT_EXCEEDED. nullable: true readOnly: true type: string x-struct: x-validate: rejected_direction: enum: - debit - credit nullable: true readOnly: true type: string x-struct: x-validate: rejected_ledger_account_id: description: LedgerAccount whose control limit was breached (NULL unless rejected). format: uuid nullable: true readOnly: true type: string x-struct: x-validate: rejected_period: enum: - daily - weekly - monthly - yearly nullable: true readOnly: true type: string x-struct: x-validate: rejected_rule: description: Rule that set the breached cap. nullable: true readOnly: true type: string x-struct: x-validate: requested_execution_date: description: Requested execution date (pain:001 ReqdExctnDt) format: date nullable: true type: string x-struct: x-validate: settlement_date: description: Actual settlement date (pacs:008 IntrBkSttlmDt / camt:054 BookgDt) format: date nullable: true type: string x-struct: x-validate: status: description: Payment lifecycle status (pain:002 / pacs:002 TxSts) enum: - pending - accepted - settled - rejected - reversed - cancelled nullable: true type: string x-struct: x-validate: status_reason_code: description: pacs:002 TxSts reason code (e.g. RJCT, ACCP, ACSC, PDNG) nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: transaction_number: description: atomic-fi-generated internal handle readOnly: true type: string x-struct: x-validate: transaction_type: description: ISO 20022 payment instruction type enum: - credit_transfer - direct_debit - card_payment - refund - reversal - internal_transfer type: string x-struct: x-validate: uetr: description: SWIFT gpi UETR (Unique End-to-End Transaction Reference — ISO 20022). Globally unique. nullable: true type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - transaction_type - amount - currency - account_holder_id - tenant_id title: TransactionResponse type: object x-order: - id - transaction_type - status - amount - currency - end_to_end_id - uetr - instruction_id - status_reason_code - requested_execution_date - settlement_date - external_id - transaction_number - rejected_ledger_account_id - rejected_period - rejected_direction - rejected_rule - rejected_code - account_holder_id - debtor_payment_account_id - creditor_payment_account_id - debtor_counterparty_id - creditor_counterparty_id - ledger_entry_id - compliance_screening_id - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.TransactionResponse x-validate: KycRequirementListResponse: description: Paginated list of kyc_requirements properties: data: description: List of kyc_requirements items: $ref: '#/components/schemas/KycRequirementResponse' type: array x-struct: x-validate: meta: $ref: '#/components/schemas/PaginationMeta' required: - data - meta title: KycRequirementListResponse type: object x-struct: Elixir.AtomicFi.OpenApiSchema.KycRequirementListResponse x-validate: LinkedLedgerAccountResponse: description: Edge in the LedgerAccount tree. Read-only — populated by a database trigger on LedgerAccount insert. Application code never writes to this table. example: from_ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 to_ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 type: ancestor properties: from_ledger_account_id: format: uuid readOnly: true type: string x-struct: x-validate: to_ledger_account_id: format: uuid readOnly: true type: string x-struct: x-validate: type: description: "Direction of the edge: `from` LA's ancestor / descendant is `to` LA." enum: - ancestor - descendant readOnly: true type: string x-struct: x-validate: readOnly: true title: LinkedLedgerAccountResponse type: object x-order: - from_ledger_account_id - to_ledger_account_id - type x-struct: Elixir.AtomicFi.OpenApiSchema.LinkedLedgerAccountResponse x-validate: ApiKeyRequest: description: Api key schema. `raw_key` is populated ONCE on create — store it securely client-side, it cannot be retrieved later. Request example: name: '' role_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: name: type: string x-struct: x-validate: role_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - tenant_id - role_id title: ApiKeyRequest type: object writeOnly: true x-order: - name - tenant_id - role_id x-struct: Elixir.AtomicFi.OpenApiSchema.ApiKeyRequest x-validate: LedgerEntryResponse: description: Debit/credit line item (ISO 20022 CdtDbtInd) on a leaf LedgerAccount. Created in balanced pairs (Σ debits = Σ credits). The propagate trigger rolls the amount + the entry's control limits up the ledger-account ancestor chain; a breached limit CHECK persists the entry :voided with the rejected_* details. example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 currency: '' entry_date: 2020-04-20 entry_type: credit external_entry_id: '' id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 limits_at_entry: - rejected_code: '' rejected_direction: debit rejected_ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 rejected_period: daily rejected_rule: '' status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 updated_at: 2020-04-20T16:20:00Z properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (e.g. cents for USD). Must be >= 0. type: integer x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from LedgerAccount → Ledger. type: string x-struct: x-validate: entry_date: description: ISO 20022 ValDt — value/settlement date format: date nullable: true type: string x-struct: x-validate: entry_type: enum: - credit - debit type: string x-struct: x-validate: external_entry_id: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: id: format: uuid readOnly: true type: string x-struct: x-validate: inserted_at: format: date-time readOnly: true type: string x-struct: x-validate: ledger_account_id: format: uuid type: string x-struct: x-validate: limits_at_entry: description: Control limits (rule engine output) for this entry's leaf account. The trigger fans these into ledger_account_balances.last_*_limit on every ancestor. items: $ref: '#/components/schemas/ControlLimitResponse' nullable: true readOnly: true type: array x-struct: x-validate: rejected_code: description: e.g. LIMIT_EXCEEDED. nullable: true readOnly: true type: string x-struct: x-validate: rejected_direction: enum: - debit - credit nullable: true readOnly: true type: string x-struct: x-validate: rejected_ledger_account_id: description: LedgerAccount whose control limit was breached (NULL unless rejected). format: uuid nullable: true readOnly: true type: string x-struct: x-validate: rejected_period: enum: - daily - weekly - monthly - yearly nullable: true readOnly: true type: string x-struct: x-validate: rejected_rule: description: Rule that set the breached cap. nullable: true readOnly: true type: string x-struct: x-validate: status: enum: - pending - posted - reversed - voided nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: updated_at: format: date-time readOnly: true type: string x-struct: x-validate: readOnly: true required: - account_holder_id - ledger_account_id - currency - amount - entry_type title: LedgerEntryResponse type: object x-order: - id - account_holder_id - ledger_account_id - currency - amount - entry_type - status - entry_date - external_entry_id - limits_at_entry - rejected_ledger_account_id - rejected_period - rejected_direction - rejected_rule - rejected_code - tenant_id - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerEntryResponse x-validate: UserRequest: description: User schema Request example: confirmed_at: 2020-04-20T16:20:00Z email: '' hashed_password: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: confirmed_at: format: date-time nullable: true type: string x-struct: x-validate: email: type: string x-struct: x-validate: hashed_password: type: string writeOnly: true x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - email - tenant_id title: UserRequest type: object writeOnly: true x-order: - email - hashed_password - confirmed_at - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.UserRequest x-validate: SanctionsMatchRequest: description: 'One Watchman / OFAC sanctions match. false_positive_qualifier persists reviewer decisions across re-screenings: :manual_override (human override) or :auto_suppressed (system dedup). ISO 20022 auth:018. Request' example: addresses: - false_positive_qualifier: none list_sources: {} list_synced_at: 2020-04-20T16:20:00Z match_score: 0.0 matched_entity_type: '' matched_name: '' review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 source_data: {} source_id: '' source_list: '' properties: addresses: items: $ref: '#/components/schemas/WatchmanAddressResponse' type: array x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: list_sources: nullable: true type: object x-struct: x-validate: list_synced_at: format: date-time nullable: true type: string x-struct: x-validate: match_score: format: float type: number x-struct: x-validate: matched_entity_type: nullable: true type: string x-struct: x-validate: matched_name: type: string x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: source_data: nullable: true type: object x-struct: x-validate: source_id: nullable: true type: string x-struct: x-validate: source_list: type: string x-struct: x-validate: required: - matched_name - match_score - source_list title: SanctionsMatchRequest type: object writeOnly: true x-order: - matched_name - matched_entity_type - match_score - source_list - source_id - source_data - addresses - false_positive_qualifier - review_notes - reviewed_by_user_id - reviewed_at - list_synced_at - list_sources x-struct: Elixir.AtomicFi.OpenApiSchema.SanctionsMatchRequest x-validate: securitySchemes: ApiKeyAuth: description: 'API key for authentication. Include as: x-api-key: your_api_key_here' in: header name: x-api-key type: apiKey info: description: | # Introduction ## Authentication All protected API endpoints require API key authentication. Include your API key in the x-api-key header: ``` x-api-key: your_api_key_here ``` ## Multi-Tenancy All resources are scoped to a tenant. Requests automatically use the tenant associated with your API key. ## Pagination List endpoints support pagination using Flop parameters: - `page_size` - Number of items per page (default: 50) - `page` - Page number (1-indexed) - `order_by` - Fields to sort by - `order_directions` - Sort directions (asc/desc) title: Payment Compliance Platform API version: 0.1.0 openapi: 3.1.0 paths: /api/compliance-screenings/screen-payment-account: post: callbacks: {} description: 'OFAC SDN Digital Currency Address screening for crypto wallets (`account_type: crypto_wallet` + `wallet_address` + `wallet_chain`). Non-crypto rails return a no-screen `pending` result. Stateless.' operationId: AtomicFiApi.ComplianceScreeningController.screen_payment_account parameters: [] requestBody: content: application/json: schema: description: 'Payment account — one row per payment instrument linked to an AccountHolder (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer rule compliance. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 account_number: '' account_type: bank_account bank_name: '' card_pan: '' counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' enabled_regimes: - "" external_id: '' iban: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_number: '' routing_number: '' status: active swift_bic: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 wallet_address: '' wallet_chain: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: account_number: description: Bank account number (PCI-DSS sensitive — tokenise before storing) nullable: true type: string x-struct: x-validate: account_type: enum: - bank_account - card - wallet - crypto_wallet type: string x-struct: x-validate: bank_name: description: Name of the account's bank nullable: true type: string x-struct: x-validate: card_pan: description: Card PAN last-4 or token (PCI-DSS — never store raw PAN) nullable: true type: string x-struct: x-validate: counterparty_id: format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: iban: description: International Bank Account Number (IBAN) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: payment_account_number: description: Opaque internal payment account number nullable: true type: string x-struct: x-validate: routing_number: description: Bank routing / sort code nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - blocked nullable: true type: string x-struct: x-validate: swift_bic: description: SWIFT/BIC code of the account's bank nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: wallet_address: description: On-chain wallet address (the actual identifier funds settle to). Set together with wallet_chain when account_type = :crypto_wallet. nullable: true type: string x-struct: x-validate: wallet_chain: description: Blockchain / asset ticker the wallet_address lives on (e.g. "BTC", "ETH", "TRON"). Disambiguates same-format addresses across chains. nullable: true type: string x-struct: x-validate: required: - account_type - account_holder_id - tenant_id title: PaymentAccountRequest type: object writeOnly: true x-order: - account_type - status - currency - account_number - routing_number - iban - swift_bic - bank_name - card_pan - wallet_address - wallet_chain - payment_account_number - external_id - account_holder_id - legal_entity_id - counterparty_id - ledger_account_id - enabled_regimes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountRequest x-validate: description: Payment account request required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Preview-screen a payment account (stateless) tags: - Compliance Screening /api/tenants/{id}: delete: callbacks: {} description: | Deletes a tenant. **Authorization**: Requires `platform_admin_api` role. **Warning**: This operation will fail if the tenant has dependent records (roles, users, etc.) due to database foreign key constraints. operationId: AtomicFiApi.TenantController.delete parameters: - description: Tenant ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Tenant deleted '403': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Insufficient permissions '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '409': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Constraint violation summary: Delete tenant tags: - Tenants get: callbacks: {} description: Returns a single tenant by ID. Tenant must belong to the authenticated user's scope. operationId: AtomicFiApi.TenantController.show parameters: - description: Tenant ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/TenantResponse' description: Tenant '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get tenant by ID tags: - Tenants put: callbacks: {} description: | Updates an existing tenant using PUT semantics (full replacement). **HTTP Method**: PUT only (PATCH not supported) **Semantics**: Send the complete resource representation. All fields should be provided. **Authorization**: Requires `platform_admin_api` role. **Security Note**: Changing `tenant_type` is not allowed for security reasons. **Required fields**: `name`, `tenant_type` operationId: AtomicFiApi.TenantController.update parameters: - description: Tenant ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Tenant schema for multi-tenancy Request example: enabled_regimes: - "" id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' slug: '' status: active tenant_type: platform updated_at: 2020-04-20T16:20:00Z properties: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: id: format: uuid type: string x-struct: x-validate: inserted_at: format: date-time type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: slug: nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - inactive type: string x-struct: x-validate: tenant_type: enum: - platform - standard type: string x-struct: x-validate: updated_at: format: date-time type: string x-struct: x-validate: required: - name - tenant_type title: TenantRequest type: object writeOnly: true x-order: - id - name - slug - status - tenant_type - metadata - enabled_regimes - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.TenantRequest x-validate: description: Tenant params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.TenantResponse description: Tenant updated '403': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Insufficient permissions '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update tenant (full replacement) tags: - Tenants /api/users: get: callbacks: {} description: | Returns a paginated list of users scoped to the authenticated tenant. Supports Flop pagination and filtering on `email`, `confirmed_at`. operationId: AtomicFiApi.UserController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/UserListResponse' description: User list summary: List users tags: - Users post: callbacks: {} description: | Creates a new user. The `hashed_password` must be pre-hashed (bcrypt) by the caller. On success, the default tenant-level `user` role is automatically assigned. operationId: AtomicFiApi.UserController.create parameters: [] requestBody: content: application/json: schema: description: User schema Request example: confirmed_at: 2020-04-20T16:20:00Z email: '' hashed_password: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: confirmed_at: format: date-time nullable: true type: string x-struct: x-validate: email: type: string x-struct: x-validate: hashed_password: type: string writeOnly: true x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - email - tenant_id title: UserRequest type: object writeOnly: true x-order: - email - hashed_password - confirmed_at - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.UserRequest x-validate: description: User params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.UserResponse description: User created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create user tags: - Users /api/compliance-screenings/screen-account-holder: post: callbacks: {} description: Stateless preview screen of an `AccountHolderRequest` (with inline `legal_entity`). No DB writes. Returns an unsaved `ComplianceScreeningResponse`. operationId: AtomicFiApi.ComplianceScreeningController.screen_account_holder parameters: [] requestBody: content: application/json: schema: description: Account holder — the MDM subject controlling an account. All PII lives in the linked LegalEntity (ISO 20022 acmt:007 / acmt:019). POST creates the LegalEntity atomically via the nested `legal_entity` object — the LE link is immutable post-create (LE carries the FK, not AH). To replace LE PII content, use `PUT /api/account-holders/:id/legal-entity`. Request example: account_holder_number: '' account_holder_type: individual chain_screening: false enabled_currencies: - "" enabled_regimes: - "" external_id: '' kyc_status: not_started last_reviewed_at: 2020-04-20T16:20:00Z legal_entity: onboarded_at: 2020-04-20T16:20:00Z risk_level: low status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_number: nullable: true type: string x-struct: x-validate: account_holder_type: enum: - individual - business - trust - nonprofit type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_currencies: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: kyc_status: enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: last_reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' onboarded_at: format: date-time nullable: true type: string x-struct: x-validate: risk_level: enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: status: enum: - pending - active - suspended - closed - flagged nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_type title: AccountHolderRequest type: object writeOnly: true x-order: - legal_entity - external_id - account_holder_type - status - kyc_status - risk_level - enabled_currencies - enabled_regimes - account_holder_number - onboarded_at - last_reviewed_at - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderRequest x-validate: description: Account holder request required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Preview-screen an account holder (stateless) tags: - Compliance Screening /api/payment-accounts/{id}: delete: callbacks: {} description: Deletes a payment account. operationId: AtomicFiApi.PaymentAccountController.delete parameters: - description: Payment account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Payment account deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete payment account tags: - Payment Accounts get: callbacks: {} description: Returns a single payment account. operationId: AtomicFiApi.PaymentAccountController.show parameters: - description: Payment account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaymentAccountResponse' description: Payment account '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get payment account by ID tags: - Payment Accounts put: callbacks: {} description: Updates an existing payment account using PUT semantics (full replacement). operationId: AtomicFiApi.PaymentAccountController.update parameters: - description: Payment account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: 'Payment account — one row per payment instrument linked to an AccountHolder (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer rule compliance. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 account_number: '' account_type: bank_account bank_name: '' card_pan: '' counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' enabled_regimes: - "" external_id: '' iban: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_number: '' routing_number: '' status: active swift_bic: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 wallet_address: '' wallet_chain: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: account_number: description: Bank account number (PCI-DSS sensitive — tokenise before storing) nullable: true type: string x-struct: x-validate: account_type: enum: - bank_account - card - wallet - crypto_wallet type: string x-struct: x-validate: bank_name: description: Name of the account's bank nullable: true type: string x-struct: x-validate: card_pan: description: Card PAN last-4 or token (PCI-DSS — never store raw PAN) nullable: true type: string x-struct: x-validate: counterparty_id: format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: iban: description: International Bank Account Number (IBAN) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: payment_account_number: description: Opaque internal payment account number nullable: true type: string x-struct: x-validate: routing_number: description: Bank routing / sort code nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - blocked nullable: true type: string x-struct: x-validate: swift_bic: description: SWIFT/BIC code of the account's bank nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: wallet_address: description: On-chain wallet address (the actual identifier funds settle to). Set together with wallet_chain when account_type = :crypto_wallet. nullable: true type: string x-struct: x-validate: wallet_chain: description: Blockchain / asset ticker the wallet_address lives on (e.g. "BTC", "ETH", "TRON"). Disambiguates same-format addresses across chains. nullable: true type: string x-struct: x-validate: required: - account_type - account_holder_id - tenant_id title: PaymentAccountRequest type: object writeOnly: true x-order: - account_type - status - currency - account_number - routing_number - iban - swift_bic - bank_name - card_pan - wallet_address - wallet_chain - payment_account_number - external_id - account_holder_id - legal_entity_id - counterparty_id - ledger_account_id - enabled_regimes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountRequest x-validate: description: Payment account params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.PaymentAccountResponse description: Payment account updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update payment account (full replacement) tags: - Payment Accounts /api/beneficial-owners: get: callbacks: {} description: | Returns a paginated list of beneficial owners scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, control_type, verification_status) operationId: AtomicFiApi.BeneficialOwnerController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/BeneficialOwnerListResponse' description: Beneficial owner list summary: List beneficial owners tags: - Beneficial Owners post: callbacks: {} description: | Creates a new beneficial owner linking a corporate AccountHolder to a LegalEntity. The `account_holder_id` must reference an existing AccountHolder in the same tenant. The `legal_entity_id` must reference an existing LegalEntity in the same tenant. Each (account_holder_id, legal_entity_id) pair must be unique. operationId: AtomicFiApi.BeneficialOwnerController.create parameters: [] requestBody: content: application/json: schema: description: Beneficial owner of a corporate account holder. ≥25% ownership triggers FinCEN CDD Rule 31 CFR §1010.230 (FATF Rec 24). All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object. The LE link is immutable post-create (LE owns the FK back). To replace LE PII, use `PUT /api/beneficial-owners/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owner_number: '' chain_screening: false control_type: shareholder external_id: '' legal_entity: ownership_pct: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 verification_status: pending properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owner_number: nullable: true type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: control_type: enum: - shareholder - director - officer - trustee type: string x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' ownership_pct: nullable: true type: number x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: verification_status: enum: - pending - verified - failed nullable: true type: string x-struct: x-validate: required: - account_holder_id - control_type title: BeneficialOwnerRequest type: object writeOnly: true x-order: - account_holder_id - external_id - legal_entity - ownership_pct - control_type - verification_status - beneficial_owner_number - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerRequest x-validate: description: Beneficial owner params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerResponse description: Beneficial owner created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create beneficial owner tags: - Beneficial Owners /api/info: get: callbacks: {} description: | Public API info endpoint that returns: - Application version (from mix.exs) - Database connectivity status (SELECT 1 query in separate process) - Current timestamp **Database check**: Creates a separate Repo process to test connectivity, which handles password rotation gracefully by establishing a fresh connection. **No authentication required.** operationId: AtomicFiApi.ApiInfoController.info parameters: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/ApiInfoResponse' description: API is healthy '500': content: application/json: schema: $ref: '#/components/schemas/ApiInfoErrorResponse' description: Database connection failed summary: API information tags: - Health /api/api-keys: get: callbacks: {} description: | Returns a paginated list of API keys scoped to the authenticated tenant. The plaintext key value is never returned — only key metadata (name, role, last_used_at). operationId: AtomicFiApi.ApiKeyController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ApiKeyListResponse' description: Api key list summary: List API keys tags: - Api Keys post: callbacks: {} description: | Creates a new API key. The plaintext key is **server-generated** and returned in the `raw_key` field of the response — this is the ONLY time the plaintext is available. Store it securely client-side; it cannot be retrieved later. To rotate a key: delete the old one and create a new one. operationId: AtomicFiApi.ApiKeyController.create parameters: [] requestBody: content: application/json: schema: description: Api key schema. `raw_key` is populated ONCE on create — store it securely client-side, it cannot be retrieved later. Request example: name: '' role_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: name: type: string x-struct: x-validate: role_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - tenant_id - role_id title: ApiKeyRequest type: object writeOnly: true x-order: - name - tenant_id - role_id x-struct: Elixir.AtomicFi.OpenApiSchema.ApiKeyRequest x-validate: description: Api key params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ApiKeyResponse description: Api key created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create API key tags: - Api Keys /api/ledgers/{id}: delete: callbacks: {} description: Deletes a ledger. operationId: AtomicFiApi.LedgerController.delete parameters: - description: Ledger ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Ledger deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete ledger tags: - Ledgers get: callbacks: {} description: Returns a single ledger. operationId: AtomicFiApi.LedgerController.show parameters: - description: Ledger ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerResponse' description: Ledger '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get ledger by ID tags: - Ledgers put: callbacks: {} description: Updates an existing ledger using PUT semantics (full replacement). operationId: AtomicFiApi.LedgerController.update parameters: - description: Ledger ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: ISO 20022 camt:052/camt:053 chart-of-accounts container — one per AccountHolder per currency. Balance is derived on-read by summing child LedgerAccount.balance values. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' ledger_number: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code (e.g. USD). Authoritative for the entire ledger hierarchy. type: string x-struct: x-validate: ledger_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - currency title: LedgerRequest type: object writeOnly: true x-order: - account_holder_id - currency - status - ledger_number - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerRequest x-validate: description: Ledger params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerResponse description: Ledger updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update ledger (full replacement) tags: - Ledgers /api/blocklist-entries: get: callbacks: {} description: | Returns a paginated list of blocklist entries scoped to the authenticated tenant. Supports Flop pagination and filtering on `scope`, `entry_type`, `active`. operationId: AtomicFiApi.BlocklistEntryController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/BlocklistEntryListResponse' description: Blocklist entry list summary: List blocklist entries tags: - Blocklist Entries post: callbacks: {} description: | Creates a new blocklist entry. The screening engine cache is refreshed automatically so the new entry takes effect immediately. operationId: AtomicFiApi.BlocklistEntryController.create parameters: [] requestBody: content: application/json: schema: description: Blocklist entry for account holder screening with tenant isolation Request example: active: false added_by_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 entry_type: exact reason: '' scope: first_name tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 term: '' properties: active: default: true type: boolean x-struct: x-validate: added_by_id: format: uuid nullable: true type: string x-struct: x-validate: entry_type: enum: - exact - regex type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: term: type: string x-struct: x-validate: required: - scope - entry_type - term - tenant_id title: BlocklistEntryRequest type: object writeOnly: true x-order: - scope - entry_type - term - reason - active - added_by_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryRequest x-validate: description: Blocklist entry params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryResponse description: Blocklist entry created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create blocklist entry tags: - Blocklist Entries /api/compliance-screenings/account-holders/{id}/screen: post: callbacks: {} description: Loads the AccountHolder, runs the full onboarding refresh pipeline (screen + RuleEngine + apply controls), persists the new screening row(s), and returns them in a paginated list envelope. operationId: AtomicFiApi.ComplianceScreeningController.screen_account_holder_by_id parameters: - description: Entity ID in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Sync re-screen an account holder by id (stateful, persists) tags: - Compliance Screening /api/counterparties/{id}/refresh: post: callbacks: {} description: | Manually re-runs the onboarding pipeline for an existing counterparty. Same `OnboardingContext.refresh/2` invoked by `AtomicFi.OnboardingWorker` on the scheduled cadence. operationId: AtomicFiApi.CounterpartyController.refresh parameters: - description: Counterparty ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/CounterpartyResponse' description: Refreshed counterparty '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Refresh counterparty onboarding tags: - Counterparties /api/blocklist-entries/{id}: delete: callbacks: {} description: Removes the blocklist entry and refreshes the screening engine cache immediately. operationId: AtomicFiApi.BlocklistEntryController.delete parameters: - description: Blocklist entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Blocklist entry deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete blocklist entry tags: - Blocklist Entries get: callbacks: {} operationId: AtomicFiApi.BlocklistEntryController.show parameters: - description: Blocklist entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/BlocklistEntryResponse' description: Blocklist entry '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get blocklist entry by ID tags: - Blocklist Entries put: callbacks: {} operationId: AtomicFiApi.BlocklistEntryController.update parameters: - description: Blocklist entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Blocklist entry for account holder screening with tenant isolation Request example: active: false added_by_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 entry_type: exact reason: '' scope: first_name tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 term: '' properties: active: default: true type: boolean x-struct: x-validate: added_by_id: format: uuid nullable: true type: string x-struct: x-validate: entry_type: enum: - exact - regex type: string x-struct: x-validate: reason: nullable: true type: string x-struct: x-validate: scope: enum: - first_name - last_name - company_name type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: term: type: string x-struct: x-validate: required: - scope - entry_type - term - tenant_id title: BlocklistEntryRequest type: object writeOnly: true x-order: - scope - entry_type - term - reason - active - added_by_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryRequest x-validate: description: Blocklist entry params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.BlocklistEntryResponse description: Blocklist entry updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update blocklist entry (full replacement) tags: - Blocklist Entries /api/compliance-screenings: get: callbacks: {} description: | Returns a paginated list of compliance screenings scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) operationId: AtomicFiApi.ComplianceScreeningController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screening list summary: List compliance screenings tags: - Compliance Screening /api/transactions/{id}: delete: callbacks: {} description: Deletes a transaction. operationId: AtomicFiApi.TransactionController.delete parameters: - description: Transaction ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Transaction deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete transaction tags: - Transactions get: callbacks: {} description: Returns a single transaction. operationId: AtomicFiApi.TransactionController.show parameters: - description: Transaction ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/TransactionResponse' description: Transaction '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get transaction by ID tags: - Transactions put: callbacks: {} description: Updates an existing transaction using PUT semantics (full replacement). operationId: AtomicFiApi.TransactionController.update parameters: - description: Transaction ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: 'Payment transaction — one row per payment instruction or transfer event. Covers pain:001 (initiation), pacs:008 (interbank), pacs:002 (status), pacs:004 (return), camt:054 (booking notification). FATF Rec 16: debtor/creditor payment accounts must be verified before settlement. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' debtor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 debtor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 end_to_end_id: '' external_id: '' instruction_id: '' ledger_entry_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requested_execution_date: 2020-04-20 settlement_date: 2020-04-20 status: pending status_reason_code: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 transaction_type: credit_transfer uetr: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (cents) — always positive type: integer x-struct: x-validate: compliance_screening_id: description: ComplianceScreening result for this transaction (auth:018 / camt:998) format: uuid nullable: true type: string x-struct: x-validate: creditor_counterparty_id: description: Creditor (payee) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: creditor_payment_account_id: description: Creditor (payee) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) type: string x-struct: x-validate: debtor_counterparty_id: description: Debtor (payer) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: debtor_payment_account_id: description: Debtor (payer) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: end_to_end_id: description: pain:001 EndToEndId — set by originating party, immutable once set nullable: true type: string x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: instruction_id: description: pain:001 TxId — instruction ID from the payment initiation message nullable: true type: string x-struct: x-validate: ledger_entry_id: description: LedgerEntry created by this transaction (camt:052/053 Ntry) format: uuid nullable: true type: string x-struct: x-validate: requested_execution_date: description: Requested execution date (pain:001 ReqdExctnDt) format: date nullable: true type: string x-struct: x-validate: settlement_date: description: Actual settlement date (pacs:008 IntrBkSttlmDt / camt:054 BookgDt) format: date nullable: true type: string x-struct: x-validate: status: description: Payment lifecycle status (pain:002 / pacs:002 TxSts) enum: - pending - accepted - settled - rejected - reversed - cancelled nullable: true type: string x-struct: x-validate: status_reason_code: description: pacs:002 TxSts reason code (e.g. RJCT, ACCP, ACSC, PDNG) nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: transaction_type: description: ISO 20022 payment instruction type enum: - credit_transfer - direct_debit - card_payment - refund - reversal - internal_transfer type: string x-struct: x-validate: uetr: description: SWIFT gpi UETR (Unique End-to-End Transaction Reference — ISO 20022). Globally unique. nullable: true type: string x-struct: x-validate: required: - transaction_type - amount - currency - account_holder_id - tenant_id title: TransactionRequest type: object writeOnly: true x-order: - transaction_type - status - amount - currency - end_to_end_id - uetr - instruction_id - status_reason_code - requested_execution_date - settlement_date - external_id - account_holder_id - debtor_payment_account_id - creditor_payment_account_id - debtor_counterparty_id - creditor_counterparty_id - ledger_entry_id - compliance_screening_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.TransactionRequest x-validate: description: Transaction params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.TransactionResponse description: Transaction updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update transaction (full replacement) tags: - Transactions /api/beneficial-owners/{id}/legal-entity: put: callbacks: {} description: | Updates the BeneficialOwner-owned LegalEntity using PUT semantics (full replacement of PII). The BO-LE link is immutable post-create. operationId: AtomicFiApi.BeneficialOwnerController.update_legal_entity parameters: - description: Beneficial owner ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Shared identity record for individuals and businesses per ISO 20022 acmt:007 + FATF CDD Request example: addresses: - business_name: '' citizenship_country: '' date_formed: 2020-04-20 date_of_birth: 2020-04-20 doing_business_as_names: - "" first_name: '' identifications: - last_name: '' legal_entity_type: individual legal_structure: corporation middle_name: '' phone_numbers: - politically_exposed_person: false preferred_name: '' prefix: '' suffix: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 website: '' properties: addresses: items: $ref: '#/components/schemas/LegalEntityAddressRequest' type: array x-struct: x-validate: business_name: nullable: true type: string x-struct: x-validate: citizenship_country: nullable: true type: string x-struct: x-validate: date_formed: format: date nullable: true type: string x-struct: x-validate: date_of_birth: format: date nullable: true type: string x-struct: x-validate: doing_business_as_names: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: first_name: nullable: true type: string x-struct: x-validate: identifications: items: $ref: '#/components/schemas/LegalEntityIdentificationRequest' type: array x-struct: x-validate: last_name: nullable: true type: string x-struct: x-validate: legal_entity_type: enum: - individual - business type: string x-struct: x-validate: legal_structure: enum: - corporation - llc - non_profit - partnership - sole_proprietorship - trust - government nullable: true type: string x-struct: x-validate: middle_name: nullable: true type: string x-struct: x-validate: phone_numbers: items: $ref: '#/components/schemas/LegalEntityPhoneNumberRequest' type: array x-struct: x-validate: politically_exposed_person: nullable: true type: boolean x-struct: x-validate: preferred_name: nullable: true type: string x-struct: x-validate: prefix: nullable: true type: string x-struct: x-validate: suffix: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: website: format: uri nullable: true type: string x-struct: x-validate: required: - legal_entity_type - tenant_id title: LegalEntityRequest type: object writeOnly: true x-order: - legal_entity_type - legal_structure - business_name - doing_business_as_names - date_formed - website - first_name - middle_name - last_name - prefix - suffix - preferred_name - date_of_birth - citizenship_country - politically_exposed_person - addresses - phone_numbers - identifications - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityRequest x-validate: description: Legal entity params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LegalEntityResponse description: Legal entity replaced '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Replace the linked LegalEntity (PII) for a beneficial owner tags: - Beneficial Owners /api/kyc-requirements/{id}: delete: callbacks: {} description: Deletes a KYC requirement. operationId: AtomicFiApi.KycRequirementController.delete parameters: - description: KYC requirement ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: KYC requirement deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete KYC requirement tags: - KYC Requirements get: callbacks: {} description: Returns a single KYC requirement. operationId: AtomicFiApi.KycRequirementController.show parameters: - description: KYC requirement ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/KycRequirementResponse' description: KYC requirement '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get KYC requirement by ID tags: - KYC Requirements put: callbacks: {} description: Updates an existing KYC requirement using PUT semantics (full replacement). operationId: AtomicFiApi.KycRequirementController.update parameters: - description: KYC requirement ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: 'KYC verification requirement — one row per compliance check at a given FATF scope. `account_holder_id` is always the MDM subject; `legal_entity_id` is the identity being verified. Natural key: (account_holder_id, legal_entity_id, scope, requirement_type). Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 deadline: 2020-04-20 document_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 kyc_requirement_number: '' legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requirement_type: identity_document scope: account_holder status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: deadline: format: date nullable: true type: string x-struct: x-validate: document_id: format: uuid nullable: true type: string x-struct: x-validate: kyc_requirement_number: nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: requirement_type: enum: - identity_document - proof_of_address - source_of_funds - business_relationship - pep_declaration - ubo_declaration - purpose_of_payment type: string x-struct: x-validate: scope: enum: - account_holder - counterparty - payment_account - beneficial_owner type: string x-struct: x-validate: status: enum: - pending - submitted - under_review - approved - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - scope - requirement_type - account_holder_id - legal_entity_id - tenant_id title: KycRequirementRequest type: object writeOnly: true x-order: - scope - requirement_type - status - deadline - kyc_requirement_number - account_holder_id - legal_entity_id - document_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.KycRequirementRequest x-validate: description: KYC requirement params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.KycRequirementResponse description: KYC requirement updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update KYC requirement (full replacement) tags: - KYC Requirements /api/compliance-screenings/screen-beneficial-owner: post: callbacks: {} description: Stateless preview screen of a `BeneficialOwnerRequest` (with inline `legal_entity`). No DB writes. operationId: AtomicFiApi.ComplianceScreeningController.screen_beneficial_owner parameters: [] requestBody: content: application/json: schema: description: Beneficial owner of a corporate account holder. ≥25% ownership triggers FinCEN CDD Rule 31 CFR §1010.230 (FATF Rec 24). All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object. The LE link is immutable post-create (LE owns the FK back). To replace LE PII, use `PUT /api/beneficial-owners/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owner_number: '' chain_screening: false control_type: shareholder external_id: '' legal_entity: ownership_pct: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 verification_status: pending properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owner_number: nullable: true type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: control_type: enum: - shareholder - director - officer - trustee type: string x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' ownership_pct: nullable: true type: number x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: verification_status: enum: - pending - verified - failed nullable: true type: string x-struct: x-validate: required: - account_holder_id - control_type title: BeneficialOwnerRequest type: object writeOnly: true x-order: - account_holder_id - external_id - legal_entity - ownership_pct - control_type - verification_status - beneficial_owner_number - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerRequest x-validate: description: Beneficial owner request required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Preview-screen a beneficial owner (stateless) tags: - Compliance Screening /api/compliance-screenings/counterparties/{id}/screen: post: callbacks: {} description: Loads the Counterparty, runs the full onboarding refresh pipeline, persists the new screening row(s), and returns them in a paginated list envelope. operationId: AtomicFiApi.ComplianceScreeningController.screen_counterparty_by_id parameters: - description: Entity ID in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Sync re-screen a counterparty by id (stateful, persists) tags: - Compliance Screening /api/transactions: get: callbacks: {} description: | Returns a paginated list of transactions scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, debtor_payment_account_id, creditor_payment_account_id, debtor_counterparty_id, creditor_counterparty_id, transaction_type, status, currency, settlement_date) operationId: AtomicFiApi.TransactionController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/TransactionListResponse' description: Transaction list summary: List transactions tags: - Transactions post: callbacks: {} description: | Creates a new payment transaction linked to an AccountHolder. Maps to ISO 20022 `pain:001` CustomerCreditTransferInitiation. FATF Recommendation 16: debtor/creditor PaymentAccounts must be verified before settlement. The orchestration layer must enforce this check. **PCI-DSS 4.0:** Raw PAN data must never appear in transaction fields. Use tokenised card references via the linked PaymentAccount only. operationId: AtomicFiApi.TransactionController.create parameters: [] requestBody: content: application/json: schema: description: 'Payment transaction — one row per payment instruction or transfer event. Covers pain:001 (initiation), pacs:008 (interbank), pacs:002 (status), pacs:004 (return), camt:054 (booking notification). FATF Rec 16: debtor/creditor payment accounts must be verified before settlement. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 creditor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' debtor_counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 debtor_payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 end_to_end_id: '' external_id: '' instruction_id: '' ledger_entry_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requested_execution_date: 2020-04-20 settlement_date: 2020-04-20 status: pending status_reason_code: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 transaction_type: credit_transfer uetr: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (cents) — always positive type: integer x-struct: x-validate: compliance_screening_id: description: ComplianceScreening result for this transaction (auth:018 / camt:998) format: uuid nullable: true type: string x-struct: x-validate: creditor_counterparty_id: description: Creditor (payee) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: creditor_payment_account_id: description: Creditor (payee) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) type: string x-struct: x-validate: debtor_counterparty_id: description: Debtor (payer) counterparty — pain:001 format: uuid nullable: true type: string x-struct: x-validate: debtor_payment_account_id: description: Debtor (payer) payment account — pain:001 format: uuid nullable: true type: string x-struct: x-validate: end_to_end_id: description: pain:001 EndToEndId — set by originating party, immutable once set nullable: true type: string x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: instruction_id: description: pain:001 TxId — instruction ID from the payment initiation message nullable: true type: string x-struct: x-validate: ledger_entry_id: description: LedgerEntry created by this transaction (camt:052/053 Ntry) format: uuid nullable: true type: string x-struct: x-validate: requested_execution_date: description: Requested execution date (pain:001 ReqdExctnDt) format: date nullable: true type: string x-struct: x-validate: settlement_date: description: Actual settlement date (pacs:008 IntrBkSttlmDt / camt:054 BookgDt) format: date nullable: true type: string x-struct: x-validate: status: description: Payment lifecycle status (pain:002 / pacs:002 TxSts) enum: - pending - accepted - settled - rejected - reversed - cancelled nullable: true type: string x-struct: x-validate: status_reason_code: description: pacs:002 TxSts reason code (e.g. RJCT, ACCP, ACSC, PDNG) nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: transaction_type: description: ISO 20022 payment instruction type enum: - credit_transfer - direct_debit - card_payment - refund - reversal - internal_transfer type: string x-struct: x-validate: uetr: description: SWIFT gpi UETR (Unique End-to-End Transaction Reference — ISO 20022). Globally unique. nullable: true type: string x-struct: x-validate: required: - transaction_type - amount - currency - account_holder_id - tenant_id title: TransactionRequest type: object writeOnly: true x-order: - transaction_type - status - amount - currency - end_to_end_id - uetr - instruction_id - status_reason_code - requested_execution_date - settlement_date - external_id - account_holder_id - debtor_payment_account_id - creditor_payment_account_id - debtor_counterparty_id - creditor_counterparty_id - ledger_entry_id - compliance_screening_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.TransactionRequest x-validate: description: Transaction params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.TransactionResponse description: Transaction created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create transaction tags: - Transactions /api/ledger-entries/{id}: delete: callbacks: {} description: | Deletes a ledger entry. NOTE: Deleting a posted entry does NOT reverse the balance. To reverse a posted entry's balance effect, update its status to `reversed` first. operationId: AtomicFiApi.LedgerEntryController.delete parameters: - description: Ledger entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Ledger entry deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete ledger entry tags: - Ledger Entries get: callbacks: {} description: Returns a single ledger entry. operationId: AtomicFiApi.LedgerEntryController.show parameters: - description: Ledger entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerEntryResponse' description: Ledger entry '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get ledger entry by ID tags: - Ledger Entries put: callbacks: {} description: | Updates an existing ledger entry using PUT semantics (full replacement). Transitioning `status` to `reversed` atomically reverses the balance delta on the parent LedgerAccount. Other status transitions (e.g. pending → posted) do not affect the balance. operationId: AtomicFiApi.LedgerEntryController.update parameters: - description: Ledger entry ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Debit/credit line item (ISO 20022 CdtDbtInd) on a leaf LedgerAccount. Created in balanced pairs (Σ debits = Σ credits). The propagate trigger rolls the amount + the entry's control limits up the ledger-account ancestor chain; a breached limit CHECK persists the entry :voided with the rejected_* details. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 currency: '' entry_date: 2020-04-20 entry_type: credit external_entry_id: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 limits_at_entry: - status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (e.g. cents for USD). Must be >= 0. type: integer x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from LedgerAccount → Ledger. type: string x-struct: x-validate: entry_date: description: ISO 20022 ValDt — value/settlement date format: date nullable: true type: string x-struct: x-validate: entry_type: enum: - credit - debit type: string x-struct: x-validate: external_entry_id: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid type: string x-struct: x-validate: limits_at_entry: description: Control limits (rule engine output) for this entry's leaf account. The trigger fans these into ledger_account_balances.last_*_limit on every ancestor. items: $ref: '#/components/schemas/ControlLimitRequest' nullable: true type: array writeOnly: true x-struct: x-validate: status: enum: - pending - posted - reversed - voided nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_account_id - currency - amount - entry_type title: LedgerEntryRequest type: object writeOnly: true x-order: - account_holder_id - ledger_account_id - currency - amount - entry_type - status - entry_date - external_entry_id - limits_at_entry - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerEntryRequest x-validate: description: Ledger entry params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerEntryResponse description: Ledger entry updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update ledger entry (full replacement) tags: - Ledger Entries /api/counterparties/{id}/legal-entity: put: callbacks: {} description: | Updates the Counterparty-owned LegalEntity using PUT semantics (full replacement of PII). The CP-LE link is immutable post-create. operationId: AtomicFiApi.CounterpartyController.update_legal_entity parameters: - description: Counterparty ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Shared identity record for individuals and businesses per ISO 20022 acmt:007 + FATF CDD Request example: addresses: - business_name: '' citizenship_country: '' date_formed: 2020-04-20 date_of_birth: 2020-04-20 doing_business_as_names: - "" first_name: '' identifications: - last_name: '' legal_entity_type: individual legal_structure: corporation middle_name: '' phone_numbers: - politically_exposed_person: false preferred_name: '' prefix: '' suffix: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 website: '' properties: addresses: items: $ref: '#/components/schemas/LegalEntityAddressRequest' type: array x-struct: x-validate: business_name: nullable: true type: string x-struct: x-validate: citizenship_country: nullable: true type: string x-struct: x-validate: date_formed: format: date nullable: true type: string x-struct: x-validate: date_of_birth: format: date nullable: true type: string x-struct: x-validate: doing_business_as_names: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: first_name: nullable: true type: string x-struct: x-validate: identifications: items: $ref: '#/components/schemas/LegalEntityIdentificationRequest' type: array x-struct: x-validate: last_name: nullable: true type: string x-struct: x-validate: legal_entity_type: enum: - individual - business type: string x-struct: x-validate: legal_structure: enum: - corporation - llc - non_profit - partnership - sole_proprietorship - trust - government nullable: true type: string x-struct: x-validate: middle_name: nullable: true type: string x-struct: x-validate: phone_numbers: items: $ref: '#/components/schemas/LegalEntityPhoneNumberRequest' type: array x-struct: x-validate: politically_exposed_person: nullable: true type: boolean x-struct: x-validate: preferred_name: nullable: true type: string x-struct: x-validate: prefix: nullable: true type: string x-struct: x-validate: suffix: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: website: format: uri nullable: true type: string x-struct: x-validate: required: - legal_entity_type - tenant_id title: LegalEntityRequest type: object writeOnly: true x-order: - legal_entity_type - legal_structure - business_name - doing_business_as_names - date_formed - website - first_name - middle_name - last_name - prefix - suffix - preferred_name - date_of_birth - citizenship_country - politically_exposed_person - addresses - phone_numbers - identifications - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityRequest x-validate: description: Legal entity params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LegalEntityResponse description: Legal entity replaced '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Replace the linked LegalEntity (PII) for a counterparty tags: - Counterparties /api/account-holders/{id}/legal-entity: put: callbacks: {} description: | Updates the AccountHolder-owned LegalEntity using PUT semantics (full replacement of PII). The AH-LE link itself is immutable post-create; this endpoint replaces the linked LE's identity fields, nested addresses, phone numbers, and identifications. operationId: AtomicFiApi.AccountHolderController.update_legal_entity parameters: - description: Account holder ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Shared identity record for individuals and businesses per ISO 20022 acmt:007 + FATF CDD Request example: addresses: - business_name: '' citizenship_country: '' date_formed: 2020-04-20 date_of_birth: 2020-04-20 doing_business_as_names: - "" first_name: '' identifications: - last_name: '' legal_entity_type: individual legal_structure: corporation middle_name: '' phone_numbers: - politically_exposed_person: false preferred_name: '' prefix: '' suffix: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 website: '' properties: addresses: items: $ref: '#/components/schemas/LegalEntityAddressRequest' type: array x-struct: x-validate: business_name: nullable: true type: string x-struct: x-validate: citizenship_country: nullable: true type: string x-struct: x-validate: date_formed: format: date nullable: true type: string x-struct: x-validate: date_of_birth: format: date nullable: true type: string x-struct: x-validate: doing_business_as_names: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: first_name: nullable: true type: string x-struct: x-validate: identifications: items: $ref: '#/components/schemas/LegalEntityIdentificationRequest' type: array x-struct: x-validate: last_name: nullable: true type: string x-struct: x-validate: legal_entity_type: enum: - individual - business type: string x-struct: x-validate: legal_structure: enum: - corporation - llc - non_profit - partnership - sole_proprietorship - trust - government nullable: true type: string x-struct: x-validate: middle_name: nullable: true type: string x-struct: x-validate: phone_numbers: items: $ref: '#/components/schemas/LegalEntityPhoneNumberRequest' type: array x-struct: x-validate: politically_exposed_person: nullable: true type: boolean x-struct: x-validate: preferred_name: nullable: true type: string x-struct: x-validate: prefix: nullable: true type: string x-struct: x-validate: suffix: nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: website: format: uri nullable: true type: string x-struct: x-validate: required: - legal_entity_type - tenant_id title: LegalEntityRequest type: object writeOnly: true x-order: - legal_entity_type - legal_structure - business_name - doing_business_as_names - date_formed - website - first_name - middle_name - last_name - prefix - suffix - preferred_name - date_of_birth - citizenship_country - politically_exposed_person - addresses - phone_numbers - identifications - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityRequest x-validate: description: Legal entity params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LegalEntityResponse description: Legal entity replaced '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Replace the linked LegalEntity (PII) for an account holder tags: - Account Holders /api/users/{id}: delete: callbacks: {} operationId: AtomicFiApi.UserController.delete parameters: - description: User ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: User deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete user tags: - Users get: callbacks: {} operationId: AtomicFiApi.UserController.show parameters: - description: User ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/UserResponse' description: User '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get user by ID tags: - Users patch: callbacks: {} operationId: AtomicFiApi.UserController.update (2) parameters: - description: User ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: User schema Request example: confirmed_at: 2020-04-20T16:20:00Z email: '' hashed_password: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: confirmed_at: format: date-time nullable: true type: string x-struct: x-validate: email: type: string x-struct: x-validate: hashed_password: type: string writeOnly: true x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - email - tenant_id title: UserRequest type: object writeOnly: true x-order: - email - hashed_password - confirmed_at - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.UserRequest x-validate: description: User params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.UserResponse description: User updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update user (full replacement) tags: - Users put: callbacks: {} operationId: AtomicFiApi.UserController.update parameters: - description: User ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: User schema Request example: confirmed_at: 2020-04-20T16:20:00Z email: '' hashed_password: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: confirmed_at: format: date-time nullable: true type: string x-struct: x-validate: email: type: string x-struct: x-validate: hashed_password: type: string writeOnly: true x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - email - tenant_id title: UserRequest type: object writeOnly: true x-order: - email - hashed_password - confirmed_at - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.UserRequest x-validate: description: User params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.UserResponse description: User updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update user (full replacement) tags: - Users /api/payment-accounts: get: callbacks: {} description: | Returns a paginated list of payment accounts scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, legal_entity_id, counterparty_id, ledger_account_id, account_type, status, currency) operationId: AtomicFiApi.PaymentAccountController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaymentAccountListResponse' description: Payment account list summary: List payment accounts tags: - Payment Accounts post: callbacks: {} description: | Creates a new payment account linked to an AccountHolder. Maps to ISO 20022 `pain:001 /`. Enables FATF Recommendation 16 (wire transfer rule) compliance by anchoring payments to a known, verified account. **PCI-DSS 4.0:** `account_number`, `iban`, and `card_pan` must be tokenised by the calling orchestration layer before writing. Never submit raw PANs. operationId: AtomicFiApi.PaymentAccountController.create parameters: [] requestBody: content: application/json: schema: description: 'Payment account — one row per payment instrument linked to an AccountHolder (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer rule compliance. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing. Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 account_number: '' account_type: bank_account bank_name: '' card_pan: '' counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' enabled_regimes: - "" external_id: '' iban: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_number: '' routing_number: '' status: active swift_bic: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 wallet_address: '' wallet_chain: '' properties: account_holder_id: format: uuid type: string x-struct: x-validate: account_number: description: Bank account number (PCI-DSS sensitive — tokenise before storing) nullable: true type: string x-struct: x-validate: account_type: enum: - bank_account - card - wallet - crypto_wallet type: string x-struct: x-validate: bank_name: description: Name of the account's bank nullable: true type: string x-struct: x-validate: card_pan: description: Card PAN last-4 or token (PCI-DSS — never store raw PAN) nullable: true type: string x-struct: x-validate: counterparty_id: format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: description: Caller-supplied SoE upsert key (unique per tenant when set) nullable: true type: string x-struct: x-validate: iban: description: International Bank Account Number (IBAN) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: payment_account_number: description: Opaque internal payment account number nullable: true type: string x-struct: x-validate: routing_number: description: Bank routing / sort code nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - blocked nullable: true type: string x-struct: x-validate: swift_bic: description: SWIFT/BIC code of the account's bank nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: wallet_address: description: On-chain wallet address (the actual identifier funds settle to). Set together with wallet_chain when account_type = :crypto_wallet. nullable: true type: string x-struct: x-validate: wallet_chain: description: Blockchain / asset ticker the wallet_address lives on (e.g. "BTC", "ETH", "TRON"). Disambiguates same-format addresses across chains. nullable: true type: string x-struct: x-validate: required: - account_type - account_holder_id - tenant_id title: PaymentAccountRequest type: object writeOnly: true x-order: - account_type - status - currency - account_number - routing_number - iban - swift_bic - bank_name - card_pan - wallet_address - wallet_chain - payment_account_number - external_id - account_holder_id - legal_entity_id - counterparty_id - ledger_account_id - enabled_regimes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PaymentAccountRequest x-validate: description: Payment account params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.PaymentAccountResponse description: Payment account created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create payment account tags: - Payment Accounts /api/compliance-screenings/{id}: delete: callbacks: {} description: Deletes a compliance screening. operationId: AtomicFiApi.ComplianceScreeningController.delete parameters: - description: Compliance screening ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Compliance screening deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete compliance screening tags: - Compliance Screening get: callbacks: {} description: Returns a single compliance screening. operationId: AtomicFiApi.ComplianceScreeningController.show parameters: - description: Compliance screening ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningResponse' description: Compliance screening '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get compliance screening by ID tags: - Compliance Screening put: callbacks: {} description: Updates a compliance screening — used for the false positive review workflow (e.g., setting false_positive_qualifier, review_notes, reviewed_by_user_id). operationId: AtomicFiApi.ComplianceScreeningController.update parameters: - description: Compliance screening ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: ISO 20022 compliance screening record (auth:018 / camt:998). One row per entity per screening run. scope controls the payment lifecycle gate; screening_type narrows the check performed. Child sanctions_matches and blocklist_matches carry per-hit detail and reviewer decisions. Request example: aml_control_count: 0 aml_control_flag: false aml_geographic_risk_flag: false aml_high_risk_country: '' aml_risk_score: 0 compliance_screening_number: '' escalation_level: 0 false_positive_qualifier: none legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 manual_review_required: false match_count: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 pep_indicator: false pep_list_name: '' review_notes: '' reviewed_at: 2020-04-20T16:20:00Z reviewed_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 sanctions_screening_date: 2020-04-20T16:20:00Z sanctions_screening_status: cleared scope: account_holder screened_at: 2020-04-20T16:20:00Z screened_entity_name: '' screened_entity_type: individual screening_rules: '' screening_score: 0 screening_status: pending screening_type: sanctions properties: aml_control_count: nullable: true type: integer x-struct: x-validate: aml_control_flag: nullable: true type: boolean x-struct: x-validate: aml_geographic_risk_flag: nullable: true type: boolean x-struct: x-validate: aml_high_risk_country: nullable: true type: string x-struct: x-validate: aml_risk_score: format: decimal nullable: true type: number x-struct: x-validate: compliance_screening_number: nullable: true type: string x-struct: x-validate: escalation_level: nullable: true type: integer x-struct: x-validate: false_positive_qualifier: enum: - none - manual_override - auto_suppressed type: string x-struct: x-validate: legal_entity_id: format: uuid nullable: true type: string x-struct: x-validate: manual_review_required: type: boolean x-struct: x-validate: match_count: nullable: true type: integer x-struct: x-validate: payment_account_id: format: uuid nullable: true type: string x-struct: x-validate: pep_indicator: nullable: true type: boolean x-struct: x-validate: pep_list_name: nullable: true type: string x-struct: x-validate: review_notes: nullable: true type: string x-struct: x-validate: reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: reviewed_by_user_id: format: uuid nullable: true type: string x-struct: x-validate: sanctions_screening_date: format: date-time nullable: true type: string x-struct: x-validate: sanctions_screening_status: enum: - cleared - pending - match - failed nullable: true type: string x-struct: x-validate: scope: enum: - account_holder - beneficial_owner - counterparty - payment_account - transaction type: string x-struct: x-validate: screened_at: format: date-time nullable: true type: string x-struct: x-validate: screened_entity_name: type: string x-struct: x-validate: screened_entity_type: enum: - individual - company - crypto_address - payment_account type: string x-struct: x-validate: screening_rules: nullable: true type: string x-struct: x-validate: screening_score: format: decimal nullable: true type: number x-struct: x-validate: screening_status: enum: - pending - pass - potential_match - blocked - escalated type: string x-struct: x-validate: screening_type: enum: - sanctions - pep - aml - adverse_media type: string x-struct: x-validate: required: - scope - screening_type - screening_status - screened_entity_type - screened_entity_name title: ComplianceScreeningRequest type: object writeOnly: true x-order: - scope - screening_type - screening_status - screening_score - screened_entity_type - screened_entity_name - match_count - screened_at - screening_rules - sanctions_screening_status - sanctions_screening_date - pep_indicator - pep_list_name - aml_risk_score - aml_control_flag - aml_control_count - aml_geographic_risk_flag - aml_high_risk_country - false_positive_qualifier - manual_review_required - reviewed_at - reviewed_by_user_id - review_notes - escalation_level - compliance_screening_number - legal_entity_id - payment_account_id x-struct: Elixir.AtomicFi.OpenApiSchema.ComplianceScreeningRequest x-validate: description: Compliance screening params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ComplianceScreeningResponse description: Compliance screening updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update compliance screening (review workflow) tags: - Compliance Screening /api/ledger-entries: get: callbacks: {} description: | Returns a paginated list of ledger entries scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (ledger_account_id, account_holder_id, entry_type, status) operationId: AtomicFiApi.LedgerEntryController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerEntryListResponse' description: Ledger entry list summary: List ledger entries tags: - Ledger Entries post: callbacks: {} description: | Creates a new ledger entry (debit or credit line) and atomically updates the parent LedgerAccount balance. - `credit` entry → balance += amount - `debit` entry → balance -= amount (returns 422 if balance would go negative — overdraft protection) Currency must match the parent LedgerAccount (which inherits from the parent Ledger). operationId: AtomicFiApi.LedgerEntryController.create parameters: [] requestBody: content: application/json: schema: description: Debit/credit line item (ISO 20022 CdtDbtInd) on a leaf LedgerAccount. Created in balanced pairs (Σ debits = Σ credits). The propagate trigger rolls the amount + the entry's control limits up the ledger-account ancestor chain; a breached limit CHECK persists the entry :voided with the rejected_* details. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 amount: 0 currency: '' entry_date: 2020-04-20 entry_type: credit external_entry_id: '' ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 limits_at_entry: - status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: amount: description: Amount in minor currency units (e.g. cents for USD). Must be >= 0. type: integer x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from LedgerAccount → Ledger. type: string x-struct: x-validate: entry_date: description: ISO 20022 ValDt — value/settlement date format: date nullable: true type: string x-struct: x-validate: entry_type: enum: - credit - debit type: string x-struct: x-validate: external_entry_id: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_account_id: format: uuid type: string x-struct: x-validate: limits_at_entry: description: Control limits (rule engine output) for this entry's leaf account. The trigger fans these into ledger_account_balances.last_*_limit on every ancestor. items: $ref: '#/components/schemas/ControlLimitRequest' nullable: true type: array writeOnly: true x-struct: x-validate: status: enum: - pending - posted - reversed - voided nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_account_id - currency - amount - entry_type title: LedgerEntryRequest type: object writeOnly: true x-order: - account_holder_id - ledger_account_id - currency - amount - entry_type - status - entry_date - external_entry_id - limits_at_entry - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerEntryRequest x-validate: description: Ledger entry params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerEntryResponse description: Ledger entry created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors or overdraft summary: Create ledger entry tags: - Ledger Entries /api/account-holders: get: callbacks: {} description: | Returns a paginated list of account holders scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_type, status, kyc_status, risk_level) operationId: AtomicFiApi.AccountHolderController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/AccountHolderListResponse' description: Account holder list summary: List account holders tags: - Account Holders post: callbacks: {} description: | Creates a new account holder linked to an existing legal entity. The `legal_entity_id` must reference an existing LegalEntity in the same tenant. operationId: AtomicFiApi.AccountHolderController.create parameters: [] requestBody: content: application/json: schema: description: Account holder — the MDM subject controlling an account. All PII lives in the linked LegalEntity (ISO 20022 acmt:007 / acmt:019). POST creates the LegalEntity atomically via the nested `legal_entity` object — the LE link is immutable post-create (LE carries the FK, not AH). To replace LE PII content, use `PUT /api/account-holders/:id/legal-entity`. Request example: account_holder_number: '' account_holder_type: individual chain_screening: false enabled_currencies: - "" enabled_regimes: - "" external_id: '' kyc_status: not_started last_reviewed_at: 2020-04-20T16:20:00Z legal_entity: onboarded_at: 2020-04-20T16:20:00Z risk_level: low status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_number: nullable: true type: string x-struct: x-validate: account_holder_type: enum: - individual - business - trust - nonprofit type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_currencies: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: kyc_status: enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: last_reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' onboarded_at: format: date-time nullable: true type: string x-struct: x-validate: risk_level: enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: status: enum: - pending - active - suspended - closed - flagged nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_type title: AccountHolderRequest type: object writeOnly: true x-order: - legal_entity - external_id - account_holder_type - status - kyc_status - risk_level - enabled_currencies - enabled_regimes - account_holder_number - onboarded_at - last_reviewed_at - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderRequest x-validate: description: Account holder params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.AccountHolderResponse description: Account holder created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create account holder tags: - Account Holders /api/compliance-screenings/screen-counterparty: post: callbacks: {} description: Stateless preview screen of a `CounterpartyRequest` (with inline `legal_entity`). No DB writes. operationId: AtomicFiApi.ComplianceScreeningController.screen_counterparty parameters: [] requestBody: content: application/json: schema: description: External payer/payee (ISO 20022 /) that an AccountHolder transacts with. All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object on POST. The LE link is immutable post-create (LE carries the FK back, not CP). To replace LE PII, use `PUT /api/counterparties/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 chain_screening: false enabled_regimes: - "" external_id: '' legal_entity: status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' status: enum: - active - suspended - blocked type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - status title: CounterpartyRequest type: object writeOnly: true x-order: - account_holder_id - legal_entity - status - external_id - enabled_regimes - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyRequest x-validate: description: Counterparty request required: true responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Preview-screen a counterparty (stateless) tags: - Compliance Screening /api/risk-classifications/{id}: delete: callbacks: {} operationId: AtomicFiApi.RiskClassificationController.delete parameters: - description: Risk classification ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Risk classification deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete risk classification tags: - Risk Classifications get: callbacks: {} operationId: AtomicFiApi.RiskClassificationController.show parameters: - description: Risk classification ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/RiskClassificationResponse' description: Risk classification '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get risk classification by ID tags: - Risk Classifications put: callbacks: {} description: | Updates an existing risk classification. When an inactive record is being activated (is_active: false → true), any other active classification for the same holder is deactivated atomically. operationId: AtomicFiApi.RiskClassificationController.update parameters: - description: Risk classification ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Formal risk classification record for an AccountHolder. Drives the LedgerAccount limit cascade. Exactly one is_active=true record exists per (holder, tenant) at a time. Maps to ISO 20022 auth:018 (CustomerRiskAssessment) and FATF Rec 10 (risk-based CDD). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 classification_reason: '' classified_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 effective_from: 2020-04-20 effective_until: 2020-04-20 is_active: false notes: '' risk_level: low tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: classification_reason: description: Human-readable justification for the classification type: string x-struct: x-validate: classified_by_user_id: description: User who performed the classification (nil = auto-classified by engine) format: uuid nullable: true type: string x-struct: x-validate: compliance_screening_id: description: ComplianceScreening that drove this classification format: uuid nullable: true type: string x-struct: x-validate: effective_from: description: Start date of the classification (inclusive) format: date type: string x-struct: x-validate: effective_until: description: End date of the classification (exclusive), nil = open-ended format: date nullable: true type: string x-struct: x-validate: is_active: default: true description: True when this is the current active classification for the holder type: boolean x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: risk_level: description: Risk level driving the LedgerAccount limit cascade enum: - low - medium - high - very_high type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - risk_level - classification_reason - effective_from - tenant_id title: RiskClassificationRequest type: object writeOnly: true x-order: - account_holder_id - risk_level - classification_reason - effective_from - effective_until - is_active - classified_by_user_id - compliance_screening_id - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RiskClassificationRequest x-validate: description: Risk classification params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.RiskClassificationResponse description: Risk classification updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update risk classification (full replacement) tags: - Risk Classifications /api/counterparties: get: callbacks: {} description: | Returns a paginated list of counterparties scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, status) operationId: AtomicFiApi.CounterpartyController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/CounterpartyListResponse' description: Counterparty list summary: List counterparties tags: - Counterparties post: callbacks: {} description: | Creates a new counterparty linking an AccountHolder to a LegalEntity. The `account_holder_id` must reference an existing AccountHolder in the same tenant. The `legal_entity_id` must reference an existing LegalEntity in the same tenant. Each (account_holder_id, legal_entity_id) pair must be unique. operationId: AtomicFiApi.CounterpartyController.create parameters: [] requestBody: content: application/json: schema: description: External payer/payee (ISO 20022 /) that an AccountHolder transacts with. All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object on POST. The LE link is immutable post-create (LE carries the FK back, not CP). To replace LE PII, use `PUT /api/counterparties/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 chain_screening: false enabled_regimes: - "" external_id: '' legal_entity: status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' status: enum: - active - suspended - blocked type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - status title: CounterpartyRequest type: object writeOnly: true x-order: - account_holder_id - legal_entity - status - external_id - enabled_regimes - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyRequest x-validate: description: Counterparty params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.CounterpartyResponse description: Counterparty created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create counterparty tags: - Counterparties /api/account-activity-snapshots: get: callbacks: {} description: | Returns a paginated list of account activity snapshots scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, payment_account_id, ledger_account_id, snapshot_type, status, currency, flagged_for_review, period_start, period_end) operationId: AtomicFiApi.AccountActivitySnapshotController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: period_start in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/AccountActivitySnapshotListResponse' description: Account activity snapshot list summary: List account activity snapshots tags: - Account Activity Snapshots post: callbacks: {} description: | Creates a new account activity snapshot linked to an AccountHolder. Maps to ISO 20022 `camt:052` (intraday) and `camt:053` (periodic statement). Use `snapshot_type: "intraday"` for on-demand account reports and `snapshot_type: "daily" | "weekly" | "monthly"` for periodic statements. **FinCEN AML:** Set `flagged_for_review: true` and populate `review_reason` when activity patterns trigger SAR thresholds (31 CFR §1020.320). operationId: AtomicFiApi.AccountActivitySnapshotController.create parameters: [] requestBody: content: application/json: schema: description: Account activity snapshot — periodic summary of debit/credit activity for an AccountHolder. Maps to ISO 20022 camt:052 (intraday account report) and camt:053 (account statement). AML fields (flagged_for_review, review_reason, sar_reference) support FinCEN SAR filing under 31 CFR §1020.320. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 closing_balance: 0 currency: '' external_reference: '' flagged_for_review: false ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 opening_balance: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 period_end: 2020-04-20T16:20:00Z period_start: 2020-04-20T16:20:00Z review_reason: '' sar_reference: '' snapshot_type: intraday status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_credit_count: 0 total_debit_amount: 0 total_debit_count: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: closing_balance: description: Balance at period end in minor currency units (camt:053 ClosingBooked) nullable: true type: integer x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: external_reference: description: Caller-supplied idempotency key (unique per tenant when set) nullable: true type: string x-struct: x-validate: flagged_for_review: description: AML review flag — true when activity patterns exceed FinCEN AML thresholds (31 CFR §1020.320 SAR requirements) type: boolean x-struct: x-validate: ledger_account_id: description: LedgerAccount scoping this snapshot (chart-of-accounts view) format: uuid nullable: true type: string x-struct: x-validate: opening_balance: description: Balance at period start in minor currency units (camt:053 OpeningBooked) nullable: true type: integer x-struct: x-validate: payment_account_id: description: PaymentAccount scoping this snapshot (camt:052/053 ) format: uuid nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: review_reason: description: Human-readable description of why this snapshot was flagged for AML review nullable: true type: string x-struct: x-validate: sar_reference: description: SAR (Suspicious Activity Report) filing reference (FinCEN SAR form 111) nullable: true type: string x-struct: x-validate: snapshot_type: description: Reporting period type — intraday maps to camt:052 (on-demand report); daily/weekly/monthly map to camt:053 (periodic statement) enum: - intraday - daily - weekly - monthly type: string x-struct: x-validate: status: description: Snapshot lifecycle status — pending (queued), computed (aggregates ready), published (sent to downstream / regulatory reporting) enum: - pending - computed - published nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount in minor currency units (camt:052/053 TtlCdtNtries Amt) type: integer x-struct: x-validate: total_credit_count: description: Number of credit entries in the period (camt:052/053 CdtNb) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount in minor currency units (camt:052/053 TtlDbtNtries Amt) type: integer x-struct: x-validate: total_debit_count: description: Number of debit entries in the period (camt:052/053 DbtNb) type: integer x-struct: x-validate: transaction_count: description: Total number of transactions (debit + credit) in the period type: integer x-struct: x-validate: required: - snapshot_type - period_start - period_end - account_holder_id - tenant_id title: AccountActivitySnapshotRequest type: object writeOnly: true x-order: - snapshot_type - period_start - period_end - opening_balance - closing_balance - currency - total_debit_count - total_credit_count - total_debit_amount - total_credit_amount - transaction_count - status - flagged_for_review - review_reason - sar_reference - external_reference - account_holder_id - payment_account_id - ledger_account_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotRequest x-validate: description: Account activity snapshot params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotResponse description: Account activity snapshot created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create account activity snapshot tags: - Account Activity Snapshots /api/ledger-account-balances/{id}: get: callbacks: {} description: | Returns a single daily balance snapshot. The snapshot is trigger-maintained and carries day/week/month/year cumulative totals and the last known control limits from the risk engine. operationId: AtomicFiApi.LedgerAccountBalanceController.show parameters: - description: Ledger account balance ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerAccountBalanceResponse' description: Ledger account balance '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get ledger account balance by ID tags: - Ledger Account Balances /api/info/normalization-rules: get: callbacks: {} description: | Returns the normalization rules used across the platform for data quality: - **titles**: List of name titles to strip (Mr., Mrs., Dr., etc.) - **suffixes**: List of name suffixes to standardize (Jr., Sr., III, etc.) - **entity_types**: List of company entity types to remove (LLC, Inc, Corp, etc.) These rules are applied during account holder screening to normalize names and company names before blocklist matching. **No authentication required.** operationId: AtomicFiApi.ApiInfoController.normalization_rules parameters: [] responses: '200': content: application/json: schema: $ref: '#/components/schemas/NormalizationRulesResponse' description: Normalization rules summary: Get normalization rules tags: - Health /api/party-activity-snapshots/{id}: delete: callbacks: {} operationId: AtomicFiApi.PartyActivitySnapshotController.delete parameters: - description: Party activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Party activity snapshot deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete party activity snapshot tags: - Party Activity Snapshots get: callbacks: {} operationId: AtomicFiApi.PartyActivitySnapshotController.show parameters: - description: Party activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/PartyActivitySnapshotResponse' description: Party activity snapshot '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get party activity snapshot by ID tags: - Party Activity Snapshots put: callbacks: {} operationId: AtomicFiApi.PartyActivitySnapshotController.update parameters: - description: Party activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Party-level AML monitoring snapshot for an AccountHolder. Captures KYC/risk transitions, screening activity, transaction shape, and SAR candidacy across a reporting window (FATF Rec 10 ongoing CDD · FinCEN 31 CFR §1020.320 SAR). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 high_risk_transaction_count: 0 kyc_status_at_end: not_started kyc_status_at_start: not_started notes: '' period_end: 2020-04-20 period_start: 2020-04-20 period_type: daily risk_level_at_end: low risk_level_at_start: low sar_indicator: false screening_hits: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_debit_amount: 0 total_screenings: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: high_risk_transaction_count: description: Transactions exceeding risk thresholds type: integer x-struct: x-validate: kyc_status_at_end: description: AccountHolder.kyc_status at period close enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: kyc_status_at_start: description: AccountHolder.kyc_status at period open enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_type: description: Reporting period cadence — daily/weekly/monthly snapshots feed ongoing CDD (FATF Rec 10); quarterly snapshots support SAR narrative evidence (FinCEN 31 CFR §1020.320). enum: - daily - weekly - monthly - quarterly type: string x-struct: x-validate: risk_level_at_end: description: AccountHolder.risk_level at period close enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: risk_level_at_start: description: AccountHolder.risk_level at period open enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: sar_indicator: description: SAR (Suspicious Activity Report) filing consideration flag type: boolean x-struct: x-validate: screening_hits: description: Potential/confirmed screening matches type: integer x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount (minor currency units) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount (minor currency units) type: integer x-struct: x-validate: total_screenings: description: Compliance screenings run in the period type: integer x-struct: x-validate: transaction_count: description: Transactions in the period type: integer x-struct: x-validate: required: - account_holder_id - period_type - period_start - period_end - tenant_id title: PartyActivitySnapshotRequest type: object writeOnly: true x-order: - account_holder_id - period_type - period_start - period_end - kyc_status_at_start - kyc_status_at_end - risk_level_at_start - risk_level_at_end - total_screenings - screening_hits - transaction_count - total_debit_amount - total_credit_amount - high_risk_transaction_count - sar_indicator - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotRequest x-validate: description: Party activity snapshot params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotResponse description: Party activity snapshot updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update party activity snapshot (full replacement) tags: - Party Activity Snapshots /api/api-keys/{id}: delete: callbacks: {} description: Revokes the API key immediately. Subsequent requests using this key will fail. operationId: AtomicFiApi.ApiKeyController.delete parameters: - description: API key ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Api key deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete API key tags: - Api Keys get: callbacks: {} operationId: AtomicFiApi.ApiKeyController.show parameters: - description: API key ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ApiKeyResponse' description: Api key '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get API key by ID tags: - Api Keys /api/risk-classifications: get: callbacks: {} description: | Returns a paginated list of risk classifications scoped to the authenticated tenant. Supports Flop filtering on account_holder_id, risk_level, is_active, effective_from/until. operationId: AtomicFiApi.RiskClassificationController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: effective_from in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/RiskClassificationListResponse' description: Risk classification list summary: List risk classifications tags: - Risk Classifications post: callbacks: {} description: | Creates a new risk classification for an AccountHolder. When `is_active: true` (the default), any previously active classification for the same holder is deactivated atomically so the single-active invariant is preserved. operationId: AtomicFiApi.RiskClassificationController.create parameters: [] requestBody: content: application/json: schema: description: Formal risk classification record for an AccountHolder. Drives the LedgerAccount limit cascade. Exactly one is_active=true record exists per (holder, tenant) at a time. Maps to ISO 20022 auth:018 (CustomerRiskAssessment) and FATF Rec 10 (risk-based CDD). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 classification_reason: '' classified_by_user_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 compliance_screening_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 effective_from: 2020-04-20 effective_until: 2020-04-20 is_active: false notes: '' risk_level: low tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: classification_reason: description: Human-readable justification for the classification type: string x-struct: x-validate: classified_by_user_id: description: User who performed the classification (nil = auto-classified by engine) format: uuid nullable: true type: string x-struct: x-validate: compliance_screening_id: description: ComplianceScreening that drove this classification format: uuid nullable: true type: string x-struct: x-validate: effective_from: description: Start date of the classification (inclusive) format: date type: string x-struct: x-validate: effective_until: description: End date of the classification (exclusive), nil = open-ended format: date nullable: true type: string x-struct: x-validate: is_active: default: true description: True when this is the current active classification for the holder type: boolean x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: risk_level: description: Risk level driving the LedgerAccount limit cascade enum: - low - medium - high - very_high type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - risk_level - classification_reason - effective_from - tenant_id title: RiskClassificationRequest type: object writeOnly: true x-order: - account_holder_id - risk_level - classification_reason - effective_from - effective_until - is_active - classified_by_user_id - compliance_screening_id - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RiskClassificationRequest x-validate: description: Risk classification params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.RiskClassificationResponse description: Risk classification created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create risk classification tags: - Risk Classifications /api/sessions: delete: callbacks: {} description: Revokes a Bearer session. Does not apply to X-API-Key sessions (rotate the API key instead). operationId: AtomicFiApi.SessionController.delete parameters: [] responses: '204': description: Session revoked '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Non-Bearer session cannot be revoked here summary: Revoke current Bearer session tags: - Auth post: callbacks: {} description: | Exchange user credentials for a Bearer token. Pass the returned `bearer` as `Authorization: Bearer ` on subsequent requests. Optional `expires_in` (seconds) controls duration (default 86400, range 60..2592000). operationId: AtomicFiApi.SessionController.create parameters: [] requestBody: content: application/json: schema: description: Authentication session. Request fields (writeOnly) carry credentials for POST /api/sessions. Response fields (readOnly) describe the resolved session. Request example: email: '' expires_in: 60 password: a tenant_slug: '' properties: email: format: email type: string writeOnly: true x-struct: x-validate: expires_in: description: Bearer session duration in seconds. Default 86400 (24h). maximum: 2592000 minimum: 60 nullable: true type: integer writeOnly: true x-struct: x-validate: password: format: password minLength: 1 type: string writeOnly: true x-struct: x-validate: tenant_slug: type: string writeOnly: true x-struct: x-validate: required: - email - password - tenant_slug title: SessionRequest type: object writeOnly: true x-order: - email - password - tenant_slug - expires_in x-struct: Elixir.AtomicFi.OpenApiSchema.SessionRequest x-validate: description: User credentials required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.SessionResponse description: Session created '401': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Invalid credentials or tenant summary: Create a Bearer session (human auth) tags: - Auth /api/roles/{id}: delete: callbacks: {} operationId: AtomicFiApi.RoleController.delete parameters: - description: Role ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Role deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete role tags: - Roles get: callbacks: {} operationId: AtomicFiApi.RoleController.show parameters: - description: Role ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/RoleResponse' description: Role '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get role by ID tags: - Roles patch: callbacks: {} operationId: AtomicFiApi.RoleController.update (2) parameters: - description: Role ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Role schema Request example: description: '' metadata: {} name: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: description: type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - description - tenant_id title: RoleRequest type: object writeOnly: true x-order: - name - description - metadata - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RoleRequest x-validate: description: Role params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.RoleResponse description: Role updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update role (full replacement) tags: - Roles put: callbacks: {} operationId: AtomicFiApi.RoleController.update parameters: - description: Role ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Role schema Request example: description: '' metadata: {} name: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: description: type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - description - tenant_id title: RoleRequest type: object writeOnly: true x-order: - name - description - metadata - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RoleRequest x-validate: description: Role params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.RoleResponse description: Role updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update role (full replacement) tags: - Roles /api/payment-accounts/{id}/refresh: post: callbacks: {} description: | Manually re-runs the onboarding pipeline for an existing payment account. Same `OnboardingContext.refresh/2` invoked by `AtomicFi.OnboardingWorker` on the scheduled cadence. operationId: AtomicFiApi.PaymentAccountController.refresh parameters: - description: Payment account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/PaymentAccountResponse' description: Refreshed payment account '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Refresh payment account onboarding tags: - Payment Accounts /api/ledger-accounts: get: callbacks: {} description: | Returns a paginated list of ledger accounts scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (ledger_id, account_holder_id, account_type, status) operationId: AtomicFiApi.LedgerAccountController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerAccountListResponse' description: Ledger account list summary: List ledger accounts tags: - Ledger Accounts post: callbacks: {} description: | Creates a new ledger account within a ledger. One ledger account per ledger per account_type (enforced by unique constraint). Currency is inherited from the parent ledger — provide the matching ISO 4217 code. Balance starts at 0 and is maintained atomically by the Ledger Entry system. operationId: AtomicFiApi.LedgerAccountController.create parameters: [] requestBody: content: application/json: schema: description: Control account in the double-entry payments ledger. `side` is the normal balance (credit-normal | debit-normal); `balance` is the running net (credits − debits), trigger-maintained. Hierarchy is captured solely in the flat ancestor_ids array; regime is a generic discriminator. Control limits live on ledger_account_balances.limits. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' la_type: account_holder_root ledger_account_number: '' ledger_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 regime: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: counterparty_id: description: Counterparty this account belongs to (NULL on master roots and PaymentAccount accounts). format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from parent Ledger. type: string x-struct: x-validate: la_type: description: Position of this row in the LedgerAccount tree. Combined with regime, determines whether this row is an aggregation root or a regime-specific child. Enforced by the ledger_accounts_la_type_shape_check CHECK constraint. enum: - account_holder_root - account_holder_regime_root - counter_party_root - counter_party_regime_root - account_holder_payment_account_root - account_holder_payment_account_regime_root - counter_party_payment_account_root - counter_party_payment_account_regime_root type: string x-struct: x-validate: ledger_account_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_id: format: uuid type: string x-struct: x-validate: payment_account_id: description: PaymentAccount this account belongs to (NULL on master roots). format: uuid nullable: true type: string x-struct: x-validate: regime: description: Generic regime discriminator (regulatory regime, fraud regime, …). Regime leaves carry the real regime name; aggregation roots carry the sentinel "root". type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_id - currency - regime title: LedgerAccountRequest type: object writeOnly: true x-order: - account_holder_id - ledger_id - currency - regime - status - ledger_account_number - payment_account_id - counterparty_id - la_type - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountRequest x-validate: description: Ledger account params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerAccountResponse description: Ledger account created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create ledger account tags: - Ledger Accounts /api/sessions/verify: get: callbacks: {} description: "Returns the current session's tenant, role, and identity. Accepts either X-API-Key or Authorization: Bearer." operationId: AtomicFiApi.SessionController.verify parameters: [] responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.SessionResponse description: Session details '401': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Invalid or missing credentials summary: Verify current session tags: - Auth /api/ledger-accounts/{id}: delete: callbacks: {} description: Deletes a ledger account. operationId: AtomicFiApi.LedgerAccountController.delete parameters: - description: Ledger account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Ledger account deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete ledger account tags: - Ledger Accounts get: callbacks: {} description: Returns a single ledger account. The `balance` field reflects the current running total in minor currency units. operationId: AtomicFiApi.LedgerAccountController.show parameters: - description: Ledger account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerAccountResponse' description: Ledger account '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get ledger account by ID tags: - Ledger Accounts put: callbacks: {} description: | Updates an existing ledger account using PUT semantics (full replacement). NOTE: `balance` is read-only and cannot be updated through this endpoint. Use the Ledger Entry endpoints to create debit/credit entries that atomically update the balance. operationId: AtomicFiApi.LedgerAccountController.update parameters: - description: Ledger account ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Control account in the double-entry payments ledger. `side` is the normal balance (credit-normal | debit-normal); `balance` is the running net (credits − debits), trigger-maintained. Hierarchy is captured solely in the flat ancestor_ids array; regime is a generic discriminator. Control limits live on ledger_account_balances.limits. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 counterparty_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' la_type: account_holder_root ledger_account_number: '' ledger_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 regime: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: counterparty_id: description: Counterparty this account belongs to (NULL on master roots and PaymentAccount accounts). format: uuid nullable: true type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code — inherited from parent Ledger. type: string x-struct: x-validate: la_type: description: Position of this row in the LedgerAccount tree. Combined with regime, determines whether this row is an aggregation root or a regime-specific child. Enforced by the ledger_accounts_la_type_shape_check CHECK constraint. enum: - account_holder_root - account_holder_regime_root - counter_party_root - counter_party_regime_root - account_holder_payment_account_root - account_holder_payment_account_regime_root - counter_party_payment_account_root - counter_party_payment_account_regime_root type: string x-struct: x-validate: ledger_account_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: ledger_id: format: uuid type: string x-struct: x-validate: payment_account_id: description: PaymentAccount this account belongs to (NULL on master roots). format: uuid nullable: true type: string x-struct: x-validate: regime: description: Generic regime discriminator (regulatory regime, fraud regime, …). Regime leaves carry the real regime name; aggregation roots carry the sentinel "root". type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - ledger_id - currency - regime title: LedgerAccountRequest type: object writeOnly: true x-order: - account_holder_id - ledger_id - currency - regime - status - ledger_account_number - payment_account_id - counterparty_id - la_type - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerAccountRequest x-validate: description: Ledger account params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerAccountResponse description: Ledger account updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update ledger account (full replacement) tags: - Ledger Accounts /api/tenants: get: callbacks: {} description: | Returns a paginated list of tenants. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by (name, slug, status, inserted_at, updated_at) - `order_directions` - Sort direction (asc or desc) Results are scoped to the authenticated tenant. operationId: AtomicFiApi.TenantController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: name in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: asc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/TenantListResponse' description: Tenant list summary: List tenants tags: - Tenants post: callbacks: {} description: | Creates a new tenant. **Authorization**: Requires `platform_admin_api` role. **Note**: Only `standard` tenant type can be created via API. Platform tenants are created via migrations only. After creation, three default roles are automatically seeded: - `tenant_admin` - Full administrative access - `tenant_user` - Default role for human users - `tenant_api` - Default role for API keys operationId: AtomicFiApi.TenantController.create parameters: [] requestBody: content: application/json: schema: description: Tenant schema for multi-tenancy Request example: enabled_regimes: - "" id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 inserted_at: 2020-04-20T16:20:00Z metadata: {} name: '' slug: '' status: active tenant_type: platform updated_at: 2020-04-20T16:20:00Z properties: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: id: format: uuid type: string x-struct: x-validate: inserted_at: format: date-time type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: slug: nullable: true type: string x-struct: x-validate: status: enum: - active - suspended - inactive type: string x-struct: x-validate: tenant_type: enum: - platform - standard type: string x-struct: x-validate: updated_at: format: date-time type: string x-struct: x-validate: required: - name - tenant_type title: TenantRequest type: object writeOnly: true x-order: - id - name - slug - status - tenant_type - metadata - enabled_regimes - inserted_at - updated_at x-struct: Elixir.AtomicFi.OpenApiSchema.TenantRequest x-validate: description: Tenant params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.TenantResponse description: Tenant created '403': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Insufficient permissions '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create tenant tags: - Tenants /api/counterparties/{id}: delete: callbacks: {} description: Deletes a counterparty. operationId: AtomicFiApi.CounterpartyController.delete parameters: - description: Counterparty ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Counterparty deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete counterparty tags: - Counterparties get: callbacks: {} description: Returns a single counterparty. operationId: AtomicFiApi.CounterpartyController.show parameters: - description: Counterparty ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/CounterpartyResponse' description: Counterparty '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get counterparty by ID tags: - Counterparties put: callbacks: {} description: Updates an existing counterparty using PUT semantics (full replacement). operationId: AtomicFiApi.CounterpartyController.update parameters: - description: Counterparty ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: External payer/payee (ISO 20022 /) that an AccountHolder transacts with. All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object on POST. The LE link is immutable post-create (LE carries the FK back, not CP). To replace LE PII, use `PUT /api/counterparties/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 chain_screening: false enabled_regimes: - "" external_id: '' legal_entity: status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' status: enum: - active - suspended - blocked type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - status title: CounterpartyRequest type: object writeOnly: true x-order: - account_holder_id - legal_entity - status - external_id - enabled_regimes - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.CounterpartyRequest x-validate: description: Counterparty params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.CounterpartyResponse description: Counterparty updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update counterparty (full replacement) tags: - Counterparties /api/account-activity-snapshots/{id}: delete: callbacks: {} description: Deletes an account activity snapshot. operationId: AtomicFiApi.AccountActivitySnapshotController.delete parameters: - description: Account activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Account activity snapshot deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete account activity snapshot tags: - Account Activity Snapshots get: callbacks: {} description: Returns a single account activity snapshot. operationId: AtomicFiApi.AccountActivitySnapshotController.show parameters: - description: Account activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/AccountActivitySnapshotResponse' description: Account activity snapshot '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get account activity snapshot by ID tags: - Account Activity Snapshots put: callbacks: {} description: Updates an existing account activity snapshot using PUT semantics (full replacement). operationId: AtomicFiApi.AccountActivitySnapshotController.update parameters: - description: Account activity snapshot ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Account activity snapshot — periodic summary of debit/credit activity for an AccountHolder. Maps to ISO 20022 camt:052 (intraday account report) and camt:053 (account statement). AML fields (flagged_for_review, review_reason, sar_reference) support FinCEN SAR filing under 31 CFR §1020.320. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 closing_balance: 0 currency: '' external_reference: '' flagged_for_review: false ledger_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 opening_balance: 0 payment_account_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 period_end: 2020-04-20T16:20:00Z period_start: 2020-04-20T16:20:00Z review_reason: '' sar_reference: '' snapshot_type: intraday status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_credit_count: 0 total_debit_amount: 0 total_debit_count: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: closing_balance: description: Balance at period end in minor currency units (camt:053 ClosingBooked) nullable: true type: integer x-struct: x-validate: currency: description: ISO 4217 3-letter currency code (e.g. USD, EUR, GBP) nullable: true type: string x-struct: x-validate: external_reference: description: Caller-supplied idempotency key (unique per tenant when set) nullable: true type: string x-struct: x-validate: flagged_for_review: description: AML review flag — true when activity patterns exceed FinCEN AML thresholds (31 CFR §1020.320 SAR requirements) type: boolean x-struct: x-validate: ledger_account_id: description: LedgerAccount scoping this snapshot (chart-of-accounts view) format: uuid nullable: true type: string x-struct: x-validate: opening_balance: description: Balance at period start in minor currency units (camt:053 OpeningBooked) nullable: true type: integer x-struct: x-validate: payment_account_id: description: PaymentAccount scoping this snapshot (camt:052/053 ) format: uuid nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date-time type: string x-struct: x-validate: review_reason: description: Human-readable description of why this snapshot was flagged for AML review nullable: true type: string x-struct: x-validate: sar_reference: description: SAR (Suspicious Activity Report) filing reference (FinCEN SAR form 111) nullable: true type: string x-struct: x-validate: snapshot_type: description: Reporting period type — intraday maps to camt:052 (on-demand report); daily/weekly/monthly map to camt:053 (periodic statement) enum: - intraday - daily - weekly - monthly type: string x-struct: x-validate: status: description: Snapshot lifecycle status — pending (queued), computed (aggregates ready), published (sent to downstream / regulatory reporting) enum: - pending - computed - published nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount in minor currency units (camt:052/053 TtlCdtNtries Amt) type: integer x-struct: x-validate: total_credit_count: description: Number of credit entries in the period (camt:052/053 CdtNb) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount in minor currency units (camt:052/053 TtlDbtNtries Amt) type: integer x-struct: x-validate: total_debit_count: description: Number of debit entries in the period (camt:052/053 DbtNb) type: integer x-struct: x-validate: transaction_count: description: Total number of transactions (debit + credit) in the period type: integer x-struct: x-validate: required: - snapshot_type - period_start - period_end - account_holder_id - tenant_id title: AccountActivitySnapshotRequest type: object writeOnly: true x-order: - snapshot_type - period_start - period_end - opening_balance - closing_balance - currency - total_debit_count - total_credit_count - total_debit_amount - total_credit_amount - transaction_count - status - flagged_for_review - review_reason - sar_reference - external_reference - account_holder_id - payment_account_id - ledger_account_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotRequest x-validate: description: Account activity snapshot params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.AccountActivitySnapshotResponse description: Account activity snapshot updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update account activity snapshot (full replacement) tags: - Account Activity Snapshots /api/ledger-account-balances: get: callbacks: {} description: | Returns a paginated list of daily balance snapshots scoped to the authenticated tenant. Balance rows are created and updated entirely by the `ledger_entry_propagate_to_balances` PostgreSQL trigger — never by application code directly. Each row carries day/week/month/year cumulative totals and the last known control limits propagated from the risk engine via the triggering ledger_entry's *_limit_at_entry snapshot. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by (balance_date, inserted_at, updated_at) - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (ledger_account_id, balance_date, iso_week, month, year) operationId: AtomicFiApi.LedgerAccountBalanceController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: balance_date in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerAccountBalanceListResponse' description: Ledger account balance list summary: List ledger account balances tags: - Ledger Account Balances /api/documents/{id}: delete: callbacks: {} description: Deletes a compliance document. operationId: AtomicFiApi.DocumentController.delete parameters: - description: Document ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Document deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete document tags: - Documents get: callbacks: {} description: Returns a single compliance document. operationId: AtomicFiApi.DocumentController.show parameters: - description: Document ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/DocumentResponse' description: Document '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get document by ID tags: - Documents put: callbacks: {} description: Updates an existing compliance document using PUT semantics (full replacement). operationId: AtomicFiApi.DocumentController.update parameters: - description: Document ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Compliance document — one row per supporting document for an AccountHolder (ISO 20022 acmt:007 SupportingDocument). Physical files are stored out-of-band; this record holds only the storage reference. At most one document may be primary per (account_holder_id, name) combination. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 content_type: '' description: '' document_number: '' document_type: identity_document file_key: '' file_name: '' file_size: 0 metadata: {} name: '' primary: false status: draft tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: content_type: nullable: true type: string x-struct: x-validate: description: nullable: true type: string x-struct: x-validate: document_number: nullable: true type: string x-struct: x-validate: document_type: enum: - identity_document - proof_of_address - source_of_funds - business_registration - ubo_declaration - pep_declaration - other type: string x-struct: x-validate: file_key: nullable: true type: string x-struct: x-validate: file_name: nullable: true type: string x-struct: x-validate: file_size: nullable: true type: integer x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: primary: type: boolean x-struct: x-validate: status: enum: - draft - submitted - under_review - accepted - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - document_type - name - primary - account_holder_id - tenant_id title: DocumentRequest type: object writeOnly: true x-order: - document_type - name - description - status - primary - file_key - file_name - file_size - content_type - document_number - metadata - account_holder_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.DocumentRequest x-validate: description: Document params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.DocumentResponse description: Document updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update document (full replacement) tags: - Documents /api/account-holders/{id}: delete: callbacks: {} description: Deletes an account holder. operationId: AtomicFiApi.AccountHolderController.delete parameters: - description: Account holder ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Account holder deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete account holder tags: - Account Holders get: callbacks: {} description: Returns a single account holder. operationId: AtomicFiApi.AccountHolderController.show parameters: - description: Account holder ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/AccountHolderResponse' description: Account holder '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get account holder by ID tags: - Account Holders put: callbacks: {} description: Updates an existing account holder using PUT semantics (full replacement). operationId: AtomicFiApi.AccountHolderController.update parameters: - description: Account holder ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Account holder — the MDM subject controlling an account. All PII lives in the linked LegalEntity (ISO 20022 acmt:007 / acmt:019). POST creates the LegalEntity atomically via the nested `legal_entity` object — the LE link is immutable post-create (LE carries the FK, not AH). To replace LE PII content, use `PUT /api/account-holders/:id/legal-entity`. Request example: account_holder_number: '' account_holder_type: individual chain_screening: false enabled_currencies: - "" enabled_regimes: - "" external_id: '' kyc_status: not_started last_reviewed_at: 2020-04-20T16:20:00Z legal_entity: onboarded_at: 2020-04-20T16:20:00Z risk_level: low status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_number: nullable: true type: string x-struct: x-validate: account_holder_type: enum: - individual - business - trust - nonprofit type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: enabled_currencies: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: enabled_regimes: items: type: string x-struct: x-validate: nullable: true type: array x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: kyc_status: enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: last_reviewed_at: format: date-time nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' onboarded_at: format: date-time nullable: true type: string x-struct: x-validate: risk_level: enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: status: enum: - pending - active - suspended - closed - flagged nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_type title: AccountHolderRequest type: object writeOnly: true x-order: - legal_entity - external_id - account_holder_type - status - kyc_status - risk_level - enabled_currencies - enabled_regimes - account_holder_number - onboarded_at - last_reviewed_at - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.AccountHolderRequest x-validate: description: Account holder params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.AccountHolderResponse description: Account holder updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update account holder (full replacement) tags: - Account Holders /api/documents: get: callbacks: {} description: | Returns a paginated list of compliance documents scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, document_type, status, primary, name) operationId: AtomicFiApi.DocumentController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/DocumentListResponse' description: Document list summary: List documents tags: - Documents post: callbacks: {} description: | Creates a new compliance document for an AccountHolder. Physical file storage is handled out-of-band — this endpoint only records the storage reference (`file_key`, `file_name`, `content_type`, `file_size`). At most one document may be `primary = true` per `(account_holder_id, name)` combination. A secondary (`primary = false`) may not be created until a primary exists. operationId: AtomicFiApi.DocumentController.create parameters: [] requestBody: content: application/json: schema: description: Compliance document — one row per supporting document for an AccountHolder (ISO 20022 acmt:007 SupportingDocument). Physical files are stored out-of-band; this record holds only the storage reference. At most one document may be primary per (account_holder_id, name) combination. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 content_type: '' description: '' document_number: '' document_type: identity_document file_key: '' file_name: '' file_size: 0 metadata: {} name: '' primary: false status: draft tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: content_type: nullable: true type: string x-struct: x-validate: description: nullable: true type: string x-struct: x-validate: document_number: nullable: true type: string x-struct: x-validate: document_type: enum: - identity_document - proof_of_address - source_of_funds - business_registration - ubo_declaration - pep_declaration - other type: string x-struct: x-validate: file_key: nullable: true type: string x-struct: x-validate: file_name: nullable: true type: string x-struct: x-validate: file_size: nullable: true type: integer x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: primary: type: boolean x-struct: x-validate: status: enum: - draft - submitted - under_review - accepted - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - document_type - name - primary - account_holder_id - tenant_id title: DocumentRequest type: object writeOnly: true x-order: - document_type - name - description - status - primary - file_key - file_name - file_size - content_type - document_number - metadata - account_holder_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.DocumentRequest x-validate: description: Document params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.DocumentResponse description: Document created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create document tags: - Documents /api/legal-entity-change-events: get: callbacks: {} description: | Returns a paginated list of legal entity change events scoped to the authenticated tenant. Change events are primarily auto-created by `update_legal_entity` and represent an append-only audit log of identity lifecycle changes (ISO 20022 acmt:006/acmt:002). Primary AML signals for account takeover detection: - `phone_change` — SIM swap attacks - `address_change` — address control patterns - `beneficiary_added` / `authorised_signer_change` — pre-transfer grooming Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (legal_entity_id, account_holder_id, beneficial_owner_id, event_type, change_channel, event_status) operationId: AtomicFiApi.LegalEntityChangeEventController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LegalEntityChangeEventListResponse' description: Legal entity change event list summary: List legal entity change events tags: - Legal Entity Change Events post: callbacks: {} description: | Creates a new legal entity change event. Use this endpoint to record externally received acmt:006 messages or to manually log identity change requests. Events auto-created by `update_legal_entity` are NOT returned in the update response — use GET /legal-entity-change-events to retrieve them. Maps to ISO 20022: - `acmt:006` — AccountModificationInstruction (via `acmt_instruction_id`) - `acmt:002` — AccountDetailsConfirmation (via `acmt_confirmation_id`) operationId: AtomicFiApi.LegalEntityChangeEventController.create parameters: [] requestBody: content: application/json: schema: description: Audit log of non-financial identity lifecycle changes to a LegalEntity. Maps to ISO 20022 acmt:006 (AccountModificationInstruction) and acmt:002 (AccountDetailsConfirmation). Auto-created by update_legal_entity via prepare_changes — not returned in the update response (requires a separate GET /legal-entity-change-events). Primary AML signal source for account takeover detection. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 acmt_confirmation_id: '' acmt_instruction_id: '' beneficial_owner_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 change_channel: web event_status: pending event_type: address_change legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: description: AccountHolder context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: acmt_confirmation_id: description: acmt:002 MsgId — confirmation message reference, populated once confirmed nullable: true type: string x-struct: x-validate: acmt_instruction_id: description: acmt:006 MsgId — upsert deduplication key. Unique per tenant when set (sparse unique index) nullable: true type: string x-struct: x-validate: beneficial_owner_id: description: BeneficialOwner context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: change_channel: description: Channel through which the modification request was received enum: - web - mobile - branch - api - phone_banking type: string x-struct: x-validate: event_status: description: Lifecycle status — pending (change requested), confirmed (verified and applied), rejected (denied by compliance / KYC check), recorded (automatically set by DB trigger for system-generated events) enum: - pending - confirmed - rejected - recorded nullable: true type: string x-struct: x-validate: event_type: description: 'Type of identity change — maps to acmt:006 MdcnCd (Modification Code). Primary AML signals: phone_change (SIM swap), address_change (address control), beneficiary_added / authorised_signer_change (pre-transfer grooming)' enum: - address_change - phone_change - email_change - beneficiary_added - beneficiary_removed - beneficiary_modified - account_inquiry - contact_info_change - authorised_signer_change type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - event_type - change_channel - legal_entity_id - tenant_id title: LegalEntityChangeEventRequest type: object writeOnly: true x-order: - event_type - change_channel - event_status - acmt_instruction_id - acmt_confirmation_id - legal_entity_id - account_holder_id - beneficial_owner_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventRequest x-validate: description: Legal entity change event params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventResponse description: Legal entity change event created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create legal entity change event tags: - Legal Entity Change Events /api/legal-entity-change-events/{id}: delete: callbacks: {} description: Deletes a legal entity change event. operationId: AtomicFiApi.LegalEntityChangeEventController.delete parameters: - description: Legal entity change event ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Legal entity change event deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete legal entity change event tags: - Legal Entity Change Events get: callbacks: {} description: Returns a single legal entity change event including JSONB diff and snapshot. operationId: AtomicFiApi.LegalEntityChangeEventController.show parameters: - description: Legal entity change event ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LegalEntityChangeEventResponse' description: Legal entity change event '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get legal entity change event by ID tags: - Legal Entity Change Events put: callbacks: {} description: | Updates mutable fields of an existing legal entity change event. Only non-system fields are mutable: `event_status`, `change_channel`, `acmt_instruction_id`, `acmt_confirmation_id`, `account_holder_id`, `beneficial_owner_id`. System-generated fields (`changes`, `previous_state`, `legal_entity_id`) are immutable after creation and are ignored even if provided. operationId: AtomicFiApi.LegalEntityChangeEventController.update parameters: - description: Legal entity change event ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Audit log of non-financial identity lifecycle changes to a LegalEntity. Maps to ISO 20022 acmt:006 (AccountModificationInstruction) and acmt:002 (AccountDetailsConfirmation). Auto-created by update_legal_entity via prepare_changes — not returned in the update response (requires a separate GET /legal-entity-change-events). Primary AML signal source for account takeover detection. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 acmt_confirmation_id: '' acmt_instruction_id: '' beneficial_owner_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 change_channel: web event_status: pending event_type: address_change legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: description: AccountHolder context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: acmt_confirmation_id: description: acmt:002 MsgId — confirmation message reference, populated once confirmed nullable: true type: string x-struct: x-validate: acmt_instruction_id: description: acmt:006 MsgId — upsert deduplication key. Unique per tenant when set (sparse unique index) nullable: true type: string x-struct: x-validate: beneficial_owner_id: description: BeneficialOwner context link (nullable — event may affect both threads) format: uuid nullable: true type: string x-struct: x-validate: change_channel: description: Channel through which the modification request was received enum: - web - mobile - branch - api - phone_banking type: string x-struct: x-validate: event_status: description: Lifecycle status — pending (change requested), confirmed (verified and applied), rejected (denied by compliance / KYC check), recorded (automatically set by DB trigger for system-generated events) enum: - pending - confirmed - rejected - recorded nullable: true type: string x-struct: x-validate: event_type: description: 'Type of identity change — maps to acmt:006 MdcnCd (Modification Code). Primary AML signals: phone_change (SIM swap), address_change (address control), beneficiary_added / authorised_signer_change (pre-transfer grooming)' enum: - address_change - phone_change - email_change - beneficiary_added - beneficiary_removed - beneficiary_modified - account_inquiry - contact_info_change - authorised_signer_change type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - event_type - change_channel - legal_entity_id - tenant_id title: LegalEntityChangeEventRequest type: object writeOnly: true x-order: - event_type - change_channel - event_status - acmt_instruction_id - acmt_confirmation_id - legal_entity_id - account_holder_id - beneficial_owner_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventRequest x-validate: description: Legal entity change event params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LegalEntityChangeEventResponse description: Legal entity change event updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update legal entity change event (mutable fields only) tags: - Legal Entity Change Events /api/party-activity-snapshots: get: callbacks: {} description: | Returns a paginated list of party activity snapshots scoped to the authenticated tenant. Supports Flop filtering on account_holder_id, period_type, period_start/end, sar_indicator. operationId: AtomicFiApi.PartyActivitySnapshotController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: period_start in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/PartyActivitySnapshotListResponse' description: Party activity snapshot list summary: List party activity snapshots tags: - Party Activity Snapshots post: callbacks: {} description: | Creates a new party activity snapshot for an AccountHolder covering a reporting window. Use daily/weekly/monthly cadence for ongoing CDD (FATF Rec 10) and quarterly for SAR-narrative evidence (FinCEN 31 CFR §1020.320). operationId: AtomicFiApi.PartyActivitySnapshotController.create parameters: [] requestBody: content: application/json: schema: description: Party-level AML monitoring snapshot for an AccountHolder. Captures KYC/risk transitions, screening activity, transaction shape, and SAR candidacy across a reporting window (FATF Rec 10 ongoing CDD · FinCEN 31 CFR §1020.320 SAR). Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 high_risk_transaction_count: 0 kyc_status_at_end: not_started kyc_status_at_start: not_started notes: '' period_end: 2020-04-20 period_start: 2020-04-20 period_type: daily risk_level_at_end: low risk_level_at_start: low sar_indicator: false screening_hits: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 total_credit_amount: 0 total_debit_amount: 0 total_screenings: 0 transaction_count: 0 properties: account_holder_id: format: uuid type: string x-struct: x-validate: high_risk_transaction_count: description: Transactions exceeding risk thresholds type: integer x-struct: x-validate: kyc_status_at_end: description: AccountHolder.kyc_status at period close enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: kyc_status_at_start: description: AccountHolder.kyc_status at period open enum: - not_started - in_progress - approved - rejected - expired nullable: true type: string x-struct: x-validate: notes: description: Free-text analyst notes nullable: true type: string x-struct: x-validate: period_end: description: End of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_start: description: Start of the reporting period (inclusive) format: date type: string x-struct: x-validate: period_type: description: Reporting period cadence — daily/weekly/monthly snapshots feed ongoing CDD (FATF Rec 10); quarterly snapshots support SAR narrative evidence (FinCEN 31 CFR §1020.320). enum: - daily - weekly - monthly - quarterly type: string x-struct: x-validate: risk_level_at_end: description: AccountHolder.risk_level at period close enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: risk_level_at_start: description: AccountHolder.risk_level at period open enum: - low - medium - high - very_high - prohibited nullable: true type: string x-struct: x-validate: sar_indicator: description: SAR (Suspicious Activity Report) filing consideration flag type: boolean x-struct: x-validate: screening_hits: description: Potential/confirmed screening matches type: integer x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: total_credit_amount: description: Total credit amount (minor currency units) type: integer x-struct: x-validate: total_debit_amount: description: Total debit amount (minor currency units) type: integer x-struct: x-validate: total_screenings: description: Compliance screenings run in the period type: integer x-struct: x-validate: transaction_count: description: Transactions in the period type: integer x-struct: x-validate: required: - account_holder_id - period_type - period_start - period_end - tenant_id title: PartyActivitySnapshotRequest type: object writeOnly: true x-order: - account_holder_id - period_type - period_start - period_end - kyc_status_at_start - kyc_status_at_end - risk_level_at_start - risk_level_at_end - total_screenings - screening_hits - transaction_count - total_debit_amount - total_credit_amount - high_risk_transaction_count - sar_indicator - notes - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotRequest x-validate: description: Party activity snapshot params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.PartyActivitySnapshotResponse description: Party activity snapshot created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create party activity snapshot tags: - Party Activity Snapshots /api/roles: get: callbacks: {} description: | Returns a paginated list of roles scoped to the authenticated tenant. Supports Flop pagination and filtering on `name`, `description`. operationId: AtomicFiApi.RoleController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/RoleListResponse' description: Role list summary: List roles tags: - Roles post: callbacks: {} description: | Creates a new role scoped to the authenticated tenant. Reserved role names (`root`, `platform_admin`, `system`, `system_api`) cannot be created through this endpoint — those are migration-managed. operationId: AtomicFiApi.RoleController.create parameters: [] requestBody: content: application/json: schema: description: Role schema Request example: description: '' metadata: {} name: '' tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: description: type: string x-struct: x-validate: metadata: nullable: true type: object x-struct: x-validate: name: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - name - description - tenant_id title: RoleRequest type: object writeOnly: true x-order: - name - description - metadata - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.RoleRequest x-validate: description: Role params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.RoleResponse description: Role created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create role tags: - Roles /api/kyc-requirements: get: callbacks: {} description: | Returns a paginated list of KYC requirements scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (scope, requirement_type, status, account_holder_id, legal_entity_id) operationId: AtomicFiApi.KycRequirementController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/KycRequirementListResponse' description: KYC requirement list summary: List KYC requirements tags: - KYC Requirements post: callbacks: {} description: | Creates a new KYC requirement linking an AccountHolder to a LegalEntity verification action. The natural key is `(account_holder_id, legal_entity_id, scope, requirement_type)` — only one requirement per combination is allowed. Optionally provide `kyc_requirement_number` for an opaque external SoE ID (must be unique per tenant when present). operationId: AtomicFiApi.KycRequirementController.create parameters: [] requestBody: content: application/json: schema: description: 'KYC verification requirement — one row per compliance check at a given FATF scope. `account_holder_id` is always the MDM subject; `legal_entity_id` is the identity being verified. Natural key: (account_holder_id, legal_entity_id, scope, requirement_type). Request' example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 deadline: 2020-04-20 document_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 kyc_requirement_number: '' legal_entity_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 requirement_type: identity_document scope: account_holder status: pending tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: deadline: format: date nullable: true type: string x-struct: x-validate: document_id: format: uuid nullable: true type: string x-struct: x-validate: kyc_requirement_number: nullable: true type: string x-struct: x-validate: legal_entity_id: format: uuid type: string x-struct: x-validate: requirement_type: enum: - identity_document - proof_of_address - source_of_funds - business_relationship - pep_declaration - ubo_declaration - purpose_of_payment type: string x-struct: x-validate: scope: enum: - account_holder - counterparty - payment_account - beneficial_owner type: string x-struct: x-validate: status: enum: - pending - submitted - under_review - approved - rejected - expired nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - scope - requirement_type - account_holder_id - legal_entity_id - tenant_id title: KycRequirementRequest type: object writeOnly: true x-order: - scope - requirement_type - status - deadline - kyc_requirement_number - account_holder_id - legal_entity_id - document_id - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.KycRequirementRequest x-validate: description: KYC requirement params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.KycRequirementResponse description: KYC requirement created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create KYC requirement tags: - KYC Requirements /api/account-holders/{id}/refresh: post: callbacks: {} description: | Manually re-runs the onboarding pipeline (screening + RuleEngine + control application) for an existing account holder. Clears the currently-scheduled rescreen job and enqueues a new one based on the engine's `next_screening_at`. Used by operator-driven re-screen flows; the same `OnboardingContext.refresh/2` is invoked by `AtomicFi.OnboardingWorker` on the scheduled cadence. operationId: AtomicFiApi.AccountHolderController.refresh parameters: - description: Account holder ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/AccountHolderResponse' description: Refreshed account holder '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Refresh account holder onboarding tags: - Account Holders /api/beneficial-owners/{id}: delete: callbacks: {} description: Deletes a beneficial owner. operationId: AtomicFiApi.BeneficialOwnerController.delete parameters: - description: Beneficial owner ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '204': description: Beneficial owner deleted '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found summary: Delete beneficial owner tags: - Beneficial Owners get: callbacks: {} description: Returns a single beneficial owner. operationId: AtomicFiApi.BeneficialOwnerController.show parameters: - description: Beneficial owner ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/BeneficialOwnerResponse' description: Beneficial owner '404': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found summary: Get beneficial owner by ID tags: - Beneficial Owners put: callbacks: {} description: Updates an existing beneficial owner using PUT semantics (full replacement). operationId: AtomicFiApi.BeneficialOwnerController.update parameters: - description: Beneficial owner ID example: 123e4567-e89b-12d3-a456-426614174000 in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: requestBody: content: application/json: schema: description: Beneficial owner of a corporate account holder. ≥25% ownership triggers FinCEN CDD Rule 31 CFR §1010.230 (FATF Rec 24). All PII lives in the linked LegalEntity, created atomically via the nested `legal_entity` object. The LE link is immutable post-create (LE owns the FK back). To replace LE PII, use `PUT /api/beneficial-owners/:id/legal-entity`. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 beneficial_owner_number: '' chain_screening: false control_type: shareholder external_id: '' legal_entity: ownership_pct: 0 tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 verification_status: pending properties: account_holder_id: format: uuid type: string x-struct: x-validate: beneficial_owner_number: nullable: true type: string x-struct: x-validate: chain_screening: default: true description: When true (default), enqueues a compliance screening job after creation. Set to false to skip. type: boolean writeOnly: true x-struct: x-validate: control_type: enum: - shareholder - director - officer - trustee type: string x-struct: x-validate: external_id: nullable: true type: string x-struct: x-validate: legal_entity: $ref: '#/components/schemas/LegalEntityRequest' ownership_pct: nullable: true type: number x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: verification_status: enum: - pending - verified - failed nullable: true type: string x-struct: x-validate: required: - account_holder_id - control_type title: BeneficialOwnerRequest type: object writeOnly: true x-order: - account_holder_id - external_id - legal_entity - ownership_pct - control_type - verification_status - beneficial_owner_number - tenant_id - chain_screening x-struct: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerRequest x-validate: description: Beneficial owner params required: true responses: '200': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.BeneficialOwnerResponse description: Beneficial owner updated '404': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ErrorResponse description: Not found '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Update beneficial owner (full replacement) tags: - Beneficial Owners /api/compliance-screenings/beneficial-owners/{id}/screen: post: callbacks: {} description: Loads the BeneficialOwner, runs the full onboarding refresh pipeline via its parent AccountHolder, persists the new screening row(s), and returns them in a paginated list envelope. operationId: AtomicFiApi.ComplianceScreeningController.screen_beneficial_owner_by_id parameters: - description: Entity ID in: path name: id required: true schema: format: uuid type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/ComplianceScreeningListResponse' description: Compliance screenings (paginated list response) '422': content: application/json: schema: $ref: '#/components/schemas/ChangesetErrors' description: Validation errors '503': content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Watchman service unavailable summary: Sync re-screen a beneficial owner by id (stateful, persists) tags: - Compliance Screening /api/tenants/refresh-blocklist-cache: post: callbacks: {} description: | Manually triggers a refresh of the blocklist cache for the authenticated tenant. This reloads all active blocklist entries from the database and rebuilds the ETS cache with optimized MapSets and combined regex patterns. **Note**: Cache is also automatically refreshed: - Every hour via Quantum scheduler - After create/update/delete operations on blocklist entries Use this endpoint when you need immediate cache refresh (e.g., after bulk imports). operationId: AtomicFiApi.TenantController.refresh_blocklist_cache parameters: [] responses: '200': content: application/json: schema: properties: message: type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: type: object x-struct: x-validate: description: Cache refreshed summary: Refresh blocklist cache tags: - Tenants /api/ledgers: get: callbacks: {} description: | Returns a paginated list of ledgers scoped to the authenticated tenant. Supports Flop pagination and filtering: - `page` - Page number (1-indexed, default: 1) - `page_size` - Items per page (default: 20, max: 100) - `order_by` - Field to sort by - `order_directions` - Sort direction (asc or desc) - `filters` - Flop filters (account_holder_id, currency, status) operationId: AtomicFiApi.LedgerController.index parameters: - description: Page number (1-indexed) example: 1 in: query name: page required: false schema: type: integer x-struct: x-validate: - description: 'Items per page (max: 100)' example: 20 in: query name: page_size required: false schema: type: integer x-struct: x-validate: - description: Field to sort by example: inserted_at in: query name: order_by required: false schema: type: string x-struct: x-validate: - description: Sort direction (asc or desc) example: desc in: query name: order_directions required: false schema: type: string x-struct: x-validate: responses: '200': content: application/json: schema: $ref: '#/components/schemas/LedgerListResponse' description: Ledger list summary: List ledgers tags: - Ledgers post: callbacks: {} description: | Creates a new ledger for an account holder in the specified currency. One ledger per account_holder per currency (enforced by unique constraint). The currency field is authoritative for the entire ledger hierarchy. operationId: AtomicFiApi.LedgerController.create parameters: [] requestBody: content: application/json: schema: description: ISO 20022 camt:052/camt:053 chart-of-accounts container — one per AccountHolder per currency. Balance is derived on-read by summing child LedgerAccount.balance values. Request example: account_holder_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 currency: '' ledger_number: '' status: active tenant_id: 02ef9c5f-29e6-48fc-9ec3-7ed57ed351f6 properties: account_holder_id: format: uuid type: string x-struct: x-validate: currency: description: ISO 4217 three-letter currency code (e.g. USD). Authoritative for the entire ledger hierarchy. type: string x-struct: x-validate: ledger_number: description: Opaque external SoE identifier (upsert identity) nullable: true type: string x-struct: x-validate: status: enum: - active - closed nullable: true type: string x-struct: x-validate: tenant_id: format: uuid type: string x-struct: x-validate: required: - account_holder_id - currency title: LedgerRequest type: object writeOnly: true x-order: - account_holder_id - currency - status - ledger_number - tenant_id x-struct: Elixir.AtomicFi.OpenApiSchema.LedgerRequest x-validate: description: Ledger params required: true responses: '201': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.LedgerResponse description: Ledger created '422': content: application/json: schema: Elixir.AtomicFi.OpenApiSchema.ChangesetErrors description: Validation errors summary: Create ledger tags: - Ledgers security: [] servers: - description: Local development (iex -S mix phx.server) url: http://localhost:4100 variables: {} tags: - description: System health and status name: Health - description: Tenant management (requires API key) name: Tenants - description: User management — email-authenticated accounts scoped to a tenant name: Users - description: Authorization roles (tenant-scoped) for users and API keys name: Roles - description: Programmatic-access API keys. Each key has exactly one role. The plaintext key is returned ONCE on create — rotate by delete + create. name: Api Keys - description: Session lifecycle for human Bearer authentication — POST /api/sessions exchanges {email,password,tenant_slug} for a Bearer token; GET /verify returns the current identity; DELETE revokes the Bearer session. X-API-Key callers do not need these endpoints. name: Auth - description: Tenant-managed internal blocklist — compliance officers add exact or regex terms to block by first_name, last_name, or company_name. The screening engine reads these at runtime via ETS cache (refreshed automatically on create/update/delete). name: Blocklist Entries - description: ISO 20022 compliance screening — sanctions (OFAC/Watchman), PEP, AML, blocklist (auth:018 / camt:998) name: Compliance Screening - description: Legal entity identity records (ISO 20022 acmt:007 + FATF CDD) name: Legal Entities - description: Account holder operational state (ISO 20022 acmt:007 / acmt:019). PII lives in the linked Legal Entity. name: Account Holders - description: Beneficial owners of corporate account holders (FinCEN CDD Rule 31 CFR §1010.230 / FATF Rec 24). PII lives in the linked Legal Entity. name: Beneficial Owners - description: External payers/payees (ISO 20022 /) that AccountHolders transact with. PII lives in the linked Legal Entity. name: Counterparties - description: ISO 20022 camt:052/camt:053 chart-of-accounts containers — one per AccountHolder per currency. name: Ledgers - description: Chart-of-accounts line items within a Ledger (asset, liability, equity, revenue, expense). Stores running balance in minor currency units — atomically updated on entry create/reverse. name: Ledger Accounts - description: Individual debit/credit line items (ISO 20022 CdtDbtInd). Creating an entry atomically updates the parent LedgerAccount balance via DB trigger. Voiding an entry (status → voided) reverses the balance delta. Control limits are enforced by DB CHECK constraints on ledger_account_balances. name: Ledger Entries - description: Daily balance snapshots for LedgerAccounts (read-only). Created and updated entirely by the ledger_entry_propagate_to_balances DB trigger. Each row carries day/week/month/year cumulative totals and last known control limits from the risk engine. Control limit enforcement is DB-driven via CHECK constraints. name: Ledger Account Balances - description: 'KYC verification requirements per FATF scope (CDD Rec 10 / EDD Rec 19 / wire Rec 16 / UBO Rec 24). One row per compliance check action — natural key: (account_holder_id, legal_entity_id, scope, requirement_type). account_holder_id is always the MDM subject; legal_entity_id is the identity being verified.' name: KYC Requirements - description: Compliance supporting documents (ISO 20022 acmt:007 SupportingDocument). Identity documents, proof of address, UBO declarations, and other KYC artefacts linked to AccountHolders. Physical files are stored out-of-band; this API manages only storage references. name: Documents - description: 'Payment accounts linked to AccountHolders (ISO 20022 pain:001 /). Gates FATF Recommendation 16 wire transfer compliance. Supports bank accounts, cards, wallets, and crypto wallets. PCI-DSS 4.0: account_number, iban, card_pan must be tokenised before writing.' name: Payment Accounts - description: 'Payment transactions linked to AccountHolders — full ISO 20022 payment lifecycle. Covers pain:001 (initiation), pacs:008 (interbank), pacs:002 (status), pacs:004 (return/refund), camt:054 (booking notification). FATF Rec 16: debtor/creditor PaymentAccounts must be verified before settlement.' name: Transactions - description: Periodic account activity summaries for AccountHolders (ISO 20022 camt:052/camt:053). Intraday snapshots map to camt:052 BankToCustomerAccountReport; daily/weekly/monthly snapshots map to camt:053 BankToCustomerStatement. AML fields (flagged_for_review, sar_reference) support FinCEN SAR filing under 31 CFR §1020.320. name: Account Activity Snapshots - description: Formal risk-level records per AccountHolder (ISO 20022 auth:018 · FATF Rec 10). Drives the LedgerAccount limit cascade — the MASTER LedgerAccount control limit is a function of the active RiskClassification.risk_level. Exactly one is_active=true record exists per (holder, tenant) at a time; creating / activating a new one deactivates the prior active record atomically. name: Risk Classifications - description: Period-level AML monitoring summaries for AccountHolders (FATF Rec 10 · FinCEN 31 CFR §1020.320). Captures KYC / risk-level transitions, screening activity, transaction shape, and SAR candidacy across a reporting window. Distinct from Account Activity Snapshots, which aggregate camt:052/053 ledger activity. name: Party Activity Snapshots - description: 'Audit log of non-financial identity lifecycle changes (ISO 20022 acmt:006/acmt:002). Auto-created by update_legal_entity via Ecto prepare_changes — captures JSONB diff and previous state. Primary AML signal source for account takeover detection: SIM swap (phone_change), address control (address_change), pre-transfer grooming (beneficiary_added/authorised_signer_change).' name: Legal Entity Change Events