SEPA libraries

Instructions

HOW-TO Use our library

All SEPA messages are identified by a code id and a name. The code id looks like FIToFICstmrCdtTrf and is located in the .xsd file describing the XML schema of the current message. The name of the message is more descriptive and looks like FIToFICustomerCreditTransfer. Both name and code id of the message are available in the SEPA messages catalogue.

For every SEPA message there is one SEPACTprocessor class. Name of the class is identical to the name of the message. For example name of the class for the message named FIToFICustomerCreditTransfer is FIToFICustomerCreditTransfer.

There are three steps the user must follow in order to build a new SEPA message:

  1. Initialize the class corresponding to the message.
  2. Add data to the class.
  3. Validate the message.

Initialize the class corresponding to the message

The initialization of the class is as simple as initializing any class in Java. For the example message we are using here (FIToFICustomerCreditTransfer) the initialization would be

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();

The above command will initialize a class for message named FIToFICustomerCreditTransfer which is initially empty.

Parsing a file

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.parseAndValidate(new File("/path/to/pacs.008.001.02.sample.xml"));

Add data to the class

Next step is to add data to the new message. In order to add some data to the message user must know which element in the message tree he wants to add. The element he wants to add is identified by an XML path. The value of the element user wants to add may be a String, a Boolean or a complex type that is described in the SEPA type catalogue.

So to enter some data into the message, user must call the following method of the class

message.setElement(path, value);

Where the path argument is a String identifying the element to add and the value argument is an Object.

User can also work with the XSD defined classes that represent a tag. e.g. GroupHeader32 for GrpHdr tag.

Validate the message

After building a SEPA message using the appropriate SEPACTprocessor class, the user may want to validate this message. Of course validation is not mandatory but is the only way to prove that the message is correct. Validation is performed by calling the validate() method of the class and internally is a two step process:

  1. Validation against the schema of the message in order to ensure that the message is a well formed instance of it.
  2. Validation against any Validation Rule as described for that message by the SEPA rules.

To perform those two levels of validation the use must call the following method

List<String> errors = message.validate();

The validate() method performs two level validation on the message and returns an ArrayList containing the validation errors that may occur. Each error is contained in the ArrayList as a String describing the error.

Manuals

SEPA Processor 5 Manual

SEPA Processor 6 Manual

Executable Demo

Download the file SEPA demo archive. It contains:

Code samples

Working with the demo

Our demo distribution comes with support for parsing/building/validating pain.001 messages. You can use our demo and see how our library works. The same code (with the equivalent classes and methods) is used for the other messages too (pacs.008, pacs.004 etc)

Parse/Validate pain.001 message

CustomerCreditTransferInitiation message = new CustomerCreditTransferInitiation();
try {
    File f = new File("/path/to/pain.001.001.03.xml");
    message.parseMessageFromXML(f);
} catch (Exception e) {
    System.err.println(e.getMessage());
    System.exit(1);
}

ArrayList<String> errors = message.validate();

try {
    System.out.println(message.get_GrpHdr_MsgId().toString());
    System.out.println(message.getElement("/GrpHdr/MsgId").toString());
    System.out.println(message.getMessageObject().getGrpHdr().getMsgId());
} catch (UnifiError e) {
    e.printStackTrace();
}

System.err.println("Message is " + ((errors.isEmpty()) ? "valid." : "invalid."));

if (!errors.isEmpty()) {
    Utils.printErrors(errors);
}

System.out.println(message.getMessageAsXML());

Working with pacs.008

Parse and validate pacs.008 message

public void parse008() throws SEPAException, Exception {
    FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();

    File file = new File("./src/test/resources/samples/eba/pacs.008.001.02.xml");
    message.parseAndValidate(file);

    System.err.println("Message is " + (message.hasValidationErrors() ? "invalid." : "valid."));

    if (message.hasValidationErrors()){
        message.printValidationErrors();
    } else {
        System.out.println(message.toString());
        System.out.println(message.getRootMessage().getGrpHdr().getMsgId());
        System.out.println(message.getElement("/GrpHdr/MsgId").toString());
    }
}

Build a pacs.008 message

FIToFICustomerCreditTransfer message = new FIToFICustomerCreditTransfer();
message.setElement("/GrpHdr/MsgId", "MESSAGEID");
message.setElement("/GrpHdr/IntrBkSttlmDt", Calendar.getInstance());
message.setElement("/GrpHdr/NbOfTxs", "1");

S2SCTCurrencyAndAmount amt = new S2SCTCurrencyAndAmount();
amt.setValue(new BigDecimal(20));
amt.setCcy(S2SCTCurrencyCode.EUR);
message.setElement("/GrpHdr/TtlIntrBkSttlmAmt", amt);

message.setElement("/GrpHdr/SttlmInf/SttlmMtd", "CLRG");
message.setElement("/GrpHdr/SttlmInf/ClrSys/Prtry", "ST2");
message.setElement("/GrpHdr/InstdAgt/FinInstnId/BIC", "MILBGRAA");

message.setElement("/CdtTrfTxInf/PmtId/InstrId", "INSTRUCTIONID");
message.setElement("/CdtTrfTxInf/PmtId/EndToEndId", "NOTPROVIDED");
message.setElement("/CdtTrfTxInf/PmtId/TxId", "TXID");
message.setElement("/CdtTrfTxInf/PmtTpInf/SvcLvl/Cd", "SEPA");

amt = new S2SCTCurrencyAndAmount();
amt.setValue(new BigDecimal(20));
amt.setCcy(S2SCTCurrencyCode.EUR);

message.setElement("/CdtTrfTxInf/IntrBkSttlmAmt", amt);
message.setElement("/CdtTrfTxInf/ChrgBr", "SLEV");

message.setElement("/CdtTrfTxInf/Dbtr/Nm", "DEBTOR NAME");
message.setElement("/CdtTrfTxInf/Dbtr/Id/OrgId/BICOrBEI", "AAAADEFFXXX");
message.setElement("/CdtTrfTxInf/DbtrAcct/Id/IBAN", "DE36500400000586060600");
message.setElement("/CdtTrfTxInf/DbtrAgt/FinInstnId/BIC", "COBADEFFXXX");

message.setElement("/CdtTrfTxInf/Cdtr/Nm", "CREDITOR NAME");
message.setElement("/CdtTrfTxInf/Cdtr/Id/OrgId/BICOrBEI", "CYDBCY2NXXX");
message.setElement("/CdtTrfTxInf/CdtrAcct/Id/IBAN", "CY21003000700000007011014888");
message.setElement("/CdtTrfTxInf/CdtrAgt/FinInstnId/BIC", "CYDBCY2N");

Returning a pacs.008

//Initialize a payment return (pacs.004)
PaymentReturn paymentReturn = new PaymentReturn();
//message id is commonly auto-generated by each system
paymentReturn.setElement("/GrpHdr/MsgId", "OURMESSAGEID");
//The settlement date for our return
paymentReturn.setElement("/GrpHdr/IntrBkSttlmDt", Calendar.getInstance());
//In most cases this is set to CLRG...
paymentReturn.setElement("/GrpHdr/SttlmInf/SttlmMtd", "CLRG");
//and Clearing system is set to ST2
paymentReturn.setElement("/GrpHdr/SttlmInf/ClrSys/Prtry", "ST2");
//Construct the message reply information
//Here we are returning a message with reason code AC01 and with no charges
//Charges have effect only for reason code FOCR (acceptance of Request for Recall)
Vector<MsgReplyInfo> msgReplyInfo = new Vector<MsgReplyInfo>();
ReasonCode rc = new ReasonCode(ReasonCode.CD, "AC01", null, null);
//The message reply info has the transaction Id of the payment we want to return, the reason code info, a return Id we generate,
//an instruction id and the settlement date of the payment that we return
MsgReplyInfo mri = new MsgReplyInfo("CB2013103008JR113303E03123860000001", rc, MsgReplyInfo.MSGID_BASED, "RETURNID", "", new Date());
msgReplyInfo.add(mri);
paymentReturn = (PaymentReturn) message.autoReply(paymentReturn, msgReplyInfo);
//and here it is
return paymentReturn.toString();

Requesting Recall for pacs.008

//Initialize a request for recall message (camt.056) with default values
FIToFIPaymentCancellationRequest fiToFIPaymentCancellationRequest = new FIToFIPaymentCancellationRequest(
    "GENERATEDASSIGNMENTID",    // the assignment id
    "XXXXXBIC",                 // the assigner bank BIC
    "YYYYYBIC"                  // the assignee bank BIC
);
//Construct the message reply information
//Here we are requesting a recall for a message with reason code DUPL (dulicate sending)
Vector<MsgReplyInfo> msgReplyInfo = new Vector<MsgReplyInfo>();
ReasonCode rc = new ReasonCode(ReasonCode.CD, "DUPL", null, null);
//The message reply info has the transaction Id of the payment we want to return, the reason code info, a return Id we generate,
//an instruction id and the settlement date of the payment.
MsgReplyInfo mri = new MsgReplyInfo("CB2013103008JR113303E03123860000001", rc, MsgReplyInfo.MSGID_BASED, "RETURNID", "", new Date());
msgReplyInfo.add(mri);
//our message is now ready to be generated!
FIToFIPaymentCancellationRequest replyMsg = (FIToFIPaymentCancellationRequest) message.autoReply(fiToFIPaymentCancellationRequest, msgReplyInfo);
//and here it is
return replyMsg.toString();

Demo

The demo web application showcases some of the functionalities of our SEPA library.

Paste or build your own message or use the predefined one. The demo application lets you: