@cfxlabsinc/b2b-services
    Preparing search index...
    WireEmailReconcileOutcome:
        | {
            bankTransactionId: string;
            ffcMemo: string
            | null;
            status: "RECONCILED";
            via: "posted" | "matched" | "enriched" | "fetched";
        }
        | { reason: string; status: "UNRESOLVED" }
        | { reason: string; status: "SKIPPED" }

    The single entry point the lambda calls once an email is stored: attach this wire to a bank transaction, whatever that takes for the bank it came from.

    Two banks, two shapes, one result:

    • burling has no transaction feed at all, so the notification IS the record — postWireEmail resolves the account from the quoted suffix and creates the row (or finds the one an operator hand-keyed).
    • fib already has rows, written by the metcap HTTP feed, and they arrive carrying nothing that identifies the wire. enrichWireEmail finds the row by the sequence number in its statement description — and when the feed has not run yet, fetchMissingBankTransaction pulls the wire straight off the metcap API and writes the row itself.

    Both end the same way: a bank transaction whose methodData holds the IMAD/OMAD, the sender, and — the part that matters downstream — the FFC memo. Returning one outcome type is what lets the caller run one deposit path and lets that path stay ignorant of which bank a wire came from. The old subsystem could not do that: it only ever handled fib, through a Hookdeck webhook that no longer exists.

    Type Declaration

    • {
          bankTransactionId: string;
          ffcMemo: string | null;
          status: "RECONCILED";
          via: "posted" | "matched" | "enriched" | "fetched";
      }
      • bankTransactionId: string
      • ffcMemo: string | null

        The customer memo this wire quoted, when it quoted one.

      • status: "RECONCILED"
      • via: "posted" | "matched" | "enriched" | "fetched"

        How the bank transaction was obtained, for the log line.

    • { reason: string; status: "UNRESOLVED" }
    • { reason: string; status: "SKIPPED" }