How To Migrate to the V2 Produced Report

The V1 Notification Service API is now deprecated and will be removed as part of the 2026.4.0 IPF release.
If you are using the Payment Notification service, you must migrate to the V2 API before then.

Why you would want to migrate

The V1 Produced Report is tightly coupled to the core IPF Supported Message Definitions, specifically the pain.001.001.09 and pain.002.001.10 definitions.

As IPF development progresses, supported for newer versions of ISO message definitions will be introduced. As a result, we cannot guarantee that the ProducedReport will function correctly when using a pain.001 message of a future version (e.g. pain.001.001.10).
A similar limitation exists the PDS objects attached to the V1 Produced Report. These objects do not specify their type or version, making it impossible for the consumer to deduce the structure of the provided PDS objects.

The V2 Produced Report is designed to be version-agnostic, ensuring compatibility regardless of the ISO message version being used or generated. Additionally, the V2 report supplies PDS type and version, enabling consumers to infer the structure of the provided PDS objects.

Data Structure Differences

The key differences between the V1 and V2 Produced Reports revolve around the versioning of produced ISO messages and PDS objects.

ISO messages

  • V1 ProducedReport:

    • The report field is of type com.iconsolutions.iso20022.message.definitions.payments_initiation.pain002.CustomerPaymentStatusReportV10

    • The pain001 field is of type com.iconsolutions.iso20022.message.definitions.payments_initiation.pain001.CustomerCreditTransferInitiationV09.

In this version, the ISO messages are tightly coupled to the specific message definitions mentioned above, reducing flexibility

  • V2 ProducedReport:

    • Both the report and pain001 fields have been updated to use the IsoMessageWrapper Java type.

    • This change decouples the produced ISO messages from exact message definitions. Instead, the wrapper provides the ISO message definition, allowing consumers to infer the structure of the underlying ISO message.

public record IsoMessageWrapper(String messageDefinition,
                                JsonNode isoMessage) {
}

PDS Objects

  • V1 ProducedReport:

    • Contains solely the name and content of a PDS object. Making the PDS content structure inference more challenging for consumers.

  • V2 ProducedReport:

    • Uses the new PdsObjectWrapper Java type which includes two new fields: typeName and version.

  • These fields enable consumers to infer the structure of the underlying PDS content more easily.

public record PdsObjectWrapper(String name,
                               String typeName,
                               Integer version,
                               JsonNode content) {
}

Removal of the NotificationEnvelope result field

The V1 NotificationEnvelope included a result field, which was used internally by the notification service application’s Resequencer. As this field is not required for the produced report, it has been removed in the V2 NotificationEnvelope model.

Comparison

Below are JSON string representations of the same produced report for both the V1 and V1 APIs.

V1 ProducedReport
{
  "uniqueId": "29786d8ae74d4f798476a068568ac5d3",
  "envelope": {
    "context": {
      "unitOfWorkId": "a9d84622-4e00-44e2-8705-7a42029c2754",
      "clientRequestId": "client-request-id-uXTNk",
      "processingEntity": "unit-of-work-KUvgO",
      "associationId": "a9d84622-4e00-44e2-8705-7a42029c2754"
    },
    "processFlowEvent": {
      "class": "com.iconsolutions.ipf.processingdata.process.ProcessFlowEvent",
      "eventId": "DebtorCT-Scheme Rules Validated-1",
      "eventName": "Scheme Rules Validated",
      "processFlowDefinitionId": "DebtorCT",
      "processFlowId": "DebtorCT",
      "causedBy": "caused-by-ipyDQ",
      "processFlowSequence": 1,
      "status": {
        "originatingStatus": "Booking",
        "resultingStatus": "Completed",
        "globalStatus": "Completed"
      },
      "reasonCode": "1",
      "reasonText": "Invalid credit account number",
      "content": "flow-event-content-MlWxm",
      "createdAt": "2025-10-31T10:26:49.690Z"
    },
    "matchingSetting": {
      "domainEvent": "Scheme Rules Validated",
      "processFlow": "DebtorCT",
      "status": "ACCC",
      "transport": "kafka",
      "endpoints": [
        {
          "topic": "PAYMENT_STATUS_NOTIFICATION"
        }
      ],
      "proprietary": "validated"
    },
    "result": {
      "completedExceptionally": false,
      "numberOfDependents": 1,
      "done": false,
      "cancelled": false
    }
  },
  "report": {
    "grpHdr": {
      "msgId": "578db9ec-d71f-43fb-9954-4320f6f4",
      "creDtTm": "2025-10-31T10:26:49.750390909Z"
    },
    "orgnlPmtInfAndSts": [
      {
        "txInfAndSts": [
          {
            "orgnlInstrId": "instrId-1",
            "txSts": "ACCC",
            "stsRsnInf": [
              {
                "rsn": {
                  "cd": "1"
                },
                "addtlInf": [ "additionalInfo" ]
              }, {
                "rsn": {
                  "prtry": "validated"
                },
                "addtlInf": [ "additionalInfo" ]
              }
            ]
          }
        ]
      }
    ],
    "orgnlGrpInfAndSts": {
      "orgnlMsgNmId": "pain.001.001.09",
      "orgnlNbOfTxs": "1"
    },
    "splmtryData": [ ]
  },
  "pain001": {
    "grpHdr": {
      "nbOfTxs": "1"
    },
    "pmtInf": [
      {
        "cdtTrfTxInf": [
          {
            "pmtId": {
              "instrId": "instrId-1"
            }
          }
        ]
      }
    ],
    "splmtryData": [ ]
  },
  "customData": [
    {
      "name": "BusinessData",
      "content": "custom-business-data"
    }, {
      "name": "IPFProcessingData",
      "content": "custom-processing-data"
    }
  ],
  "pdsData": [
    {
      "name": "Csm",
      "content": {
        "value": "STET"
      }
    }, {
      "name": "ClientSpecificBusinessData",
      "content": {
        "someField": "someValue"
      }
    }
  ]
}
V2 ProducedReport
{
  "uniqueId": "29786d8ae74d4f798476a068568ac5d3",
  "envelope": {
    "context": {
      "unitOfWorkId": "a9d84622-4e00-44e2-8705-7a42029c2754",
      "clientRequestId": "client-request-id-uXTNk",
      "processingEntity": "unit-of-work-KUvgO",
      "associationId": "a9d84622-4e00-44e2-8705-7a42029c2754"
    },
    "processFlowEvent": {
      "eventId": "DebtorCT-Scheme Rules Validated-1",
      "eventName": "Scheme Rules Validated",
      "processFlowDefinitionId": "DebtorCT",
      "processFlowId": "DebtorCT",
      "causedBy": "caused-by-ipyDQ",
      "processFlowSequence": 1,
      "status": {
        "originatingStatus": "Booking",
        "resultingStatus": "Completed",
        "globalStatus": "Completed"
      },
      "reasonCode": "1",
      "reasonText": "Invalid credit account number",
      "content": "flow-event-content-MlWxm",
      "createdAt": "2025-10-31T10:26:49.690Z"
    },
    "matchingSetting": {
      "domainEvent": "Scheme Rules Validated",
      "processFlow": "DebtorCT",
      "status": "ACCC",
      "transport": "kafka",
      "endpoints": [
        {
          "topic": "PAYMENT_STATUS_NOTIFICATION"
        }
      ],
      "proprietary": "validated"
    }
  },
  "report": {
    "messageDefinition": "pain.002.001.10",
    "isoMessage": {
      "grpHdr": {
        "msgId": "578db9ec-d71f-43fb-9954-4320f6f4",
        "creDtTm": "2025-10-31T10:26:49.750390909Z"
      },
      "orgnlPmtInfAndSts": [
        {
          "txInfAndSts": [
            {
              "orgnlInstrId": "instrId-1",
              "txSts": "ACCC",
              "stsRsnInf": [
                {
                  "rsn": {
                    "cd": "1"
                  },
                  "addtlInf": [ "additionalInfo" ]
                }, {
                  "rsn": {
                    "prtry": "validated"
                  },
                  "addtlInf": [ "additionalInfo" ]
                }
              ]
            }
          ]
        }
      ],
      "orgnlGrpInfAndSts": {
        "orgnlMsgNmId": "pain.001.001.09",
        "orgnlNbOfTxs": "1"
      }
    }
  },
  "pain001": {
    "messageDefinition": "pain.001.001.09",
    "isoMessage": {
      "grpHdr": {
        "nbOfTxs": "1"
      },
      "pmtInf": [
        {
          "cdtTrfTxInf": [
            {
              "pmtId": {
                "instrId": "instrId-1"
              }
            }
          ]
        }
      ],
      "splmtryData": [ ]
    }
  },
  "customData": [
    {
      "name": "BusinessData",
      "content": "custom-business-data"
    }, {
      "name": "IPFProcessingData",
      "content": "custom-processing-data"
    }
  ],
  "pdsData": [
    {
      "name": "Csm",
      "typeName": "Csm",
      "version": 1,
      "content": {
        "value": "STET"
      }
    }, {
      "name": "ClientSpecificBusinessData",
      "typeName": "ClientJavaClass",
      "version": 3,
      "content": {
        "someField": "someValue"
      }
    }
  ]
}

ProducedReport Java Type Maps

To aid with the adoption of the new model, we provide the complete mappings for Java references.

IMPORTANT

The new model leverages Java records, which introduce a key change in how fields are accessed. Fields previously accessed using getters are now accessed directly by name:

  • Old: producedReport.getEnvelope()

  • New: producedReport.envelope()

Old Model New Model

com.iconsolutions.ipf.product.notification.api.model.ProducedReport

com.iconsolutions.ipf.product.notification.api.model.v2.ProducedReport

com.iconsolutions.ipf.product.notification.api.model.NotificationEnvelope

com.iconsolutions.ipf.product.notification.api.model.v2.NotificationEnvelope

com.iconsolutions.ipf.core.shared.domain.context.ProcessingContext

com.iconsolutions.ipf.product.notification.api.model.v2.ProcessingContext

com.iconsolutions.ipf.processingdata.process.ProcessFlowEvent

com.iconsolutions.ipf.product.notification.api.model.v2.ProcessFlowEvent

com.iconsolutions.ipf.core.shared.domain.event.Status

com.iconsolutions.ipf.product.notification.api.model.v2.ProcessFlowEvent.Status

com.iconsolutions.ipf.product.notification.api.model.PaymentStatusNotification

com.iconsolutions.ipf.product.notification.api.model.v2.PaymentStatusNotification

com.iconsolutions.ipf.product.notification.api.model.Endpoint

com.iconsolutions.ipf.product.notification.api.model.v2.Endpoint

com.iconsolutions.ipf.processingdata.custom.CustomObjectWrapper

com.iconsolutions.ipf.product.notification.api.model.v2.CustomObjectWrapper

com.iconsolutions.ipf.product.notification.api.model.PdsObjectWrapper

com.iconsolutions.ipf.product.notification.api.model.v2.PdsObjectWrapper

Steps to Migrate

Update Payment Notification Service Config to produce V1 messages

By default, the notification service will emit a V2 ProducedReport. The first thing to do before adopting the latest version will be to configure the application to keep emitting a V1 ProducedReport while you update your consumer.

payment-status-notification.schema-version = 1

Update Consumer

Before you can start producing messages from the Notification Service using the V2 model, you must first update your consuming application to be able to handle the V2 messages.

The payload created by Notification Service contains the header ipf_schema_version, the value of which will define what version of the ProducedReport model is contained within.

Message Header Description

ipf_schema_version = 2

The inbound message utilises the V2 Produced Report model

ipf_schema_version = 1

The inbound message utilises the V1 Produced Report model

ipf_schema_version is not set

The inbound message utilises the V1 Produced Report model. This will have originated from a previous version of the Notification Service that only contained the V1 data model.

When updating a consumer of Notification Service messages, you should add a check for the ipf_schema_version header to identify which data model version to utilise when handling the inbound message.

Refer to data structure differences for a detailed comparison between the V1 and V2 models.

Once your consuming application is able to handle V2 messages, you can update the Payment Notification Service to start producing V2 messages.

Update Extension Points

If you have built client-specific notification service and have overridden any of the V1 extension points, you will need to supply the V2 equivalent for each.

NOTE

If both V1 and V2 extension points are provided, the V2 implementation is used by default.

Extension Point Java Type Maps

To aid with the adoption of the new extension points, we provide the complete mappings for Java references.

Old Model New Model

com.iconsolutions.ipf.product.notification.api.handler.AdditionalMdsObjectHandler

com.iconsolutions.ipf.product.notification.api.handler.v2.AdditionalMdsObjectHandler

com.iconsolutions.ipf.product.notification.api.processor.PostEventProcessor

com.iconsolutions.ipf.product.notification.api.processor.v2.PostEventProcessor

MessageLogEntryEnricher<com.iconsolutions.ipf.product.notification.api.model.ProducedReport>

MessageLogEntryEnricher<com.iconsolutions.ipf.product.notification.api.model.v2.ProducedReport>

SendTransportMessageConverter<com.iconsolutions.ipf.product.notification.api.model.ProducedReport>

SendTransportMessageConverter<com.iconsolutions.ipf.product.notification.api.model.v2.ProducedReport>

Update Payment Notification Service Config to produce V2 messages

Now that your consumer is able to handle V2 ProducedReport messages, you can configure the notification service application to produce V2 messages.
You can do this by removing the previously configured value:

payment-status-notification.schema-version = 1

You can either remove the line entirely or update its value as follows:

payment-status-notification.schema-version = 2