Skip to content

Mbanq/go-fedwire

Repository files navigation

go-fedwire

Go library for marshaling and unmarshaling Fedwire Funds Service ISO 20022 messages.

This is a fork of moov-io/fedwire20022 maintained by Mbanq, with the following additions:

  • Correct namespace handling — struct tags use local names only, so xml.Marshal and xml.Unmarshal work without post-processing string replacements
  • fedwirefunds_incoming/marshal.goMarshalXML implementations for all message types sent from a participant bank to FedWire
  • fedwirefunds_outgoing/unmarshal.goUnmarshalXML on FedwireFundsOutgoing container; reads MsgDefIdr from AppHdr and dispatches to the correct typed struct automatically

Naming convention

The XSD package names reflect FedWire's perspective, not the participant bank's:

Package FedWire perspective Bank perspective
fedwirefunds_incoming Messages flowing INTO FedWire Messages the bank sends
fedwirefunds_outgoing Messages flowing OUT of FedWire Messages the bank receives

Usage

Sending a message to FedWire

Build a typed struct from fedwirefunds_incoming, then call xml.MarshalMarshalXML handles namespace placement automatically:

import (
    "encoding/xml"
    "github.com/Mbanq/go-fedwire/gen/fedwirefunds_incoming"
    "github.com/Mbanq/go-fedwire/gen/head_001_001_03"
    "github.com/Mbanq/go-fedwire/gen/pacs_008_001_08"
)

msg := &fedwirefunds_incoming.FedwireFundsCustomerCreditTransfer{
    AppHdr:   head_001_001_03.BusinessApplicationHeaderV03{ ... },
    Document: pacs_008_001_08.Document{ ... },
}

if err := msg.Validate(); err != nil {
    return err
}

data, err := xml.MarshalIndent(msg, "", "  ")

Produces:

<Message xmlns="urn:fedwirefunds:incoming:v001">
  <AppHdr xmlns="urn:iso:std:iso:20022:tech:xsd:head.001.001.03">...</AppHdr>
  <Document xmlns="urn:iso:std:iso:20022:tech:xsd:pacs.008.001.08">...</Document>
</Message>

Receiving a message from FedWire

Unmarshal raw XML into FedwireFundsOutgoingUnmarshalXML reads MsgDefIdr and sets exactly one typed pointer on the message container:

import "github.com/Mbanq/go-fedwire/gen/fedwirefunds_outgoing"

var envelope fedwirefunds_outgoing.FedwireFundsOutgoing
if err := xml.Unmarshal(data, &envelope); err != nil {
    return err
}

m := envelope.FedwireFundsOutgoingMessage
switch {
case m.FedwireFundsPaymentReturn != nil:
    // pacs.004 — payment return
case m.FedwireFundsPaymentStatus != nil:
    // pacs.002 — payment status report
case m.FedwireFundsCustomerCreditTransfer != nil:
    // pacs.008 — incoming credit transfer from another bank
}

Mandatory vs optional fields

Pointer fields are optional (minOccurs="0" in XSD), value fields are mandatory (minOccurs="1"):

type CreditTransferTransaction39 struct {
    PmtId          PaymentIdentification7           // mandatory — value type
    IntrBkSttlmAmt ActiveCurrencyAndAmount          // mandatory — value type
    IntrBkSttlmDt  *fedwire.ISODate                 // optional  — pointer
    InstdAmt       *ActiveOrHistoricCurrencyAndAmount // optional  — pointer
}

Call msg.Validate() to check all required fields before marshaling.

Code generation

The gen/ packages are generated from XSD schemas in xsd/. To regenerate:

make generate

Custom files (marshal.go, unmarshal.go) are not touched by the generator and survive regeneration. The struct tag fix in model.tgo is baked into the template and applied on every generation run.

Attribution

This project is a fork of moov-io/fedwire20022, originally developed by Moov Financial, Inc. under the Apache 2.0 License.