Skip to main content

Approve a Transaction


This section explains how ImPAI handles approval of SEPA Instant (SCT Inst) transactions that require manual authorization under the Four-Eyes Principle. The approval step is part of the platform’s compliance and risk-control framework and is triggered whenever a message enters the Approval Pending state during processing.

The following message categories may require approval, depending on configuration and workflow rules:

  • Payment Instruction  – a newly submitted outgoing credit transfer.

  • Recall  – a request to undo a previously sent payment.

  • Return  – a financial return initiated by a receiving bank.

  • Resolution  – a response to a previously issued recall.

Each approval operation follows a standardized pattern:
an authorized user (checker) submits a decision to either approve or reject the pending transaction, after which ImPAI validates the request, applies business rules, records the action, and forwards the workflow to the next appropriate state.

Below you will find the dedicated approval endpoints for each message type, along with their required request fields and response formats.


Common Approval Pattern​

Although each message type (Instruction, Recall, Return, Resolution) has its own endpoint and may differ in details, they all follow a similar approval model:

β‘  Identify the transaction​

Each approval request includes one or more identifiers that uniquely reference the message to be approved or rejected.
Commonly this is an internal ID created by ImPAI (for example the Global Id / Internal Id) and may be accompanied by other message-specific identifiers.

β‘‘ Decide on an action​

The approval request carries the decision:

  • approve – release the transaction for further processing and execution
  • reject – stop processing and record the rejection reason

For rejections, a reason text is typically required to support audit and investigation.

β‘’ System behaviour​

For all four message types, the approval services:

  • Validate that the transaction is still in a state where it can be approved or rejected.
  • Check that the caller is properly authenticated and authorized.
  • Update the transaction state to Approved or Rejected.
  • Write audit information (who approved/rejected, when, and why).
  • Trigger any follow-up processing (e.g. forwarding to clearing, status updates, or closing workflows).

1️⃣ Instruction Approval​

Approval of Payment Instructions (ISO 20022 pain.001 β†’ pacs.008) is used when an initiated SEPA Instant payment requires manual release under Four-Eyes control.

Request Structure

❢  identifiers

The identifiers section provides references to the message that requires approval:

FieldTypeRequiredDescriptionConstraints
internalIdStringYesInternal identifier of the SCT_INST message to be processed. Must reference a previously created instruction, recall, return, or resolution message.1-36 chars, e.g. PAI1500002433134

❢  ApprovalDetails

The ApprovalDetails section specifies the action to be taken and optional rejection reasoning:

FieldTypeRequiredDescriptionConstraints
actionStringYesThe action to be performed on the message.Enum:
approve
reject
rejectReasonStringNoReason for rejection. Required only when action is reject.Max 512 chars, e.g. "Suspicious transaction pattern"
Response Structure
🟒 Success β€” HTTP 200

Approval or rejection was accepted by the system and its state updated. The HTTP 200 – OK response may include updated identifiers and/or a pain.002 status message.

This returns a response with the following structure:

For Successful Approval/Rejection with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00",
"DbtrAgt": {
"FinInstnId": {
// ... financial institution details
}
}
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "PNDG",
"StsRsnInf": [
// ... status reason information
]
},
"OrgnlPmtInfAndSts": [
// ... original payment information and status
]
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

For Simple Success Response:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"success": {
"status": "Success",
"transactionid": "PAI1500004121533"
}
}
πŸ”΄ Error β€” HTTP 400

In case of a validation or logical error (e.g. wrong state, missing fields), the API responds with the following structure for HTTP 400 – Bad Request errors:

Error with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00"
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "RJCT",
"StsRsnInf": [
// ... rejection reason information
]
}
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

Timeout Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"error": {
"message": "Timeout while waiting for response"
}
}

Field Validation Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"fields": [
{
"fieldMap": "/Document/CstmrCdtTrfInitn/PmtInf/0/CdtTrfTxInf/0/UltmtCdtr/Id/OrgId",
"reasonCode": "FF01",
"reasonText": "expected string, but got object"
}
]
}
🟑 Error β€” HTTP 500

Responses for HTTP 500 β€” Server Error errors are returned on unexpected server-side failures and contain:

GroupDescription
errorCodeApplication-level error identifier (e.g. 500_INTERNAL_ERROR)
messageBrief description such as "Time-out" or "Something went wrong"

Example:

{
"errorCode": "500_INTERNAL_ERROR",
"message": "Something went wrong"
}

2️⃣ Recall Approval​

Approval of Recalls is used when a previously sent SEPA Instant payment has been recalled (ISO 20022 camt.056) and that recall operation itself requires authorization.

Request Structure

❢  identifiers

The identifiers section provides references to the message that requires approval:

FieldTypeRequiredDescriptionConstraints
internalIdStringYesInternal identifier of the SCT_INST message to be processed. Must reference a previously created instruction, recall, return, or resolution message.1-36 chars, e.g. PAI1500002433134

❢  ApprovalDetails

The ApprovalDetails section specifies the action to be taken and optional rejection reasoning:

FieldTypeRequiredDescriptionConstraints
actionStringYesThe action to be performed on the message.Enum:
approve
reject
rejectReasonStringNoReason for rejection. Required only when action is reject.Max 512 chars, e.g. "Suspicious transaction pattern"
Response Structure
🟒 Success β€” HTTP 200

Approval or rejection was accepted by the system and its state updated. The HTTP 200 – OK response may include updated identifiers and/or a pain.002 status message.

This returns a response with the following structure:

For Successful Approval/Rejection with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00",
"DbtrAgt": {
"FinInstnId": {
// ... financial institution details
}
}
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "PNDG",
"StsRsnInf": [
// ... status reason information
]
},
"OrgnlPmtInfAndSts": [
// ... original payment information and status
]
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

For Simple Success Response:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"success": {
"status": "Success",
"transactionid": "PAI1500004121533"
}
}
πŸ”΄ Error β€” HTTP 400

In case of a validation or logical error (e.g. wrong state, missing fields), the API responds with the following structure for HTTP 400 – Bad Request errors:

Error with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00"
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "RJCT",
"StsRsnInf": [
// ... rejection reason information
]
}
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

Timeout Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"error": {
"message": "Timeout while waiting for response"
}
}

Field Validation Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"fields": [
{
"fieldMap": "/Document/CstmrCdtTrfInitn/PmtInf/0/CdtTrfTxInf/0/UltmtCdtr/Id/OrgId",
"reasonCode": "FF01",
"reasonText": "expected string, but got object"
}
]
}
🟑 Error β€” HTTP 500

Responses for HTTP 500 β€” Server Error errors are returned on unexpected server-side failures and contain:

GroupDescription
errorCodeApplication-level error identifier (e.g. 500_INTERNAL_ERROR)
messageBrief description such as "Time-out" or "Something went wrong"

Example:

{
"errorCode": "500_INTERNAL_ERROR",
"message": "Something went wrong"
}
POST/api/sct-inst/v1/recall/approvalApprove or Reject a Recall

3️⃣ Return Approval​

Approval of Returns is used when a payment is being sent back (ISO 20022 pacs.004) and this operation must be confirmed by an authorized user.

Request Structure

❢  identifiers

The identifiers section provides references to the message that requires approval:

FieldTypeRequiredDescriptionConstraints
internalIdStringYesInternal identifier of the SCT_INST message to be processed. Must reference a previously created instruction, recall, return, or resolution message.1-36 chars, e.g. PAI1500002433134

❢  ApprovalDetails

The ApprovalDetails section specifies the action to be taken and optional rejection reasoning:

FieldTypeRequiredDescriptionConstraints
actionStringYesThe action to be performed on the message.Enum:
approve
reject
rejectReasonStringNoReason for rejection. Required only when action is reject.Max 512 chars, e.g. "Suspicious transaction pattern"
Response Structure
🟒 Success β€” HTTP 200

Approval or rejection was accepted by the system and its state updated. The HTTP 200 – OK response may include updated identifiers and/or a pain.002 status message.

This returns a response with the following structure:

For Successful Approval/Rejection with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00",
"DbtrAgt": {
"FinInstnId": {
// ... financial institution details
}
}
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "PNDG",
"StsRsnInf": [
// ... status reason information
]
},
"OrgnlPmtInfAndSts": [
// ... original payment information and status
]
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

For Simple Success Response:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"success": {
"status": "Success",
"transactionid": "PAI1500004121533"
}
}
πŸ”΄ Error β€” HTTP 400

In case of a validation or logical error (e.g. wrong state, missing fields), the API responds with the following structure for HTTP 400 – Bad Request errors:

Error with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00"
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "RJCT",
"StsRsnInf": [
// ... rejection reason information
]
}
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

Timeout Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"error": {
"message": "Timeout while waiting for response"
}
}

Field Validation Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"fields": [
{
"fieldMap": "/Document/CstmrCdtTrfInitn/PmtInf/0/CdtTrfTxInf/0/UltmtCdtr/Id/OrgId",
"reasonCode": "FF01",
"reasonText": "expected string, but got object"
}
]
}
🟑 Error β€” HTTP 500

Responses for HTTP 500 β€” Server Error errors are returned on unexpected server-side failures and contain:

GroupDescription
errorCodeApplication-level error identifier (e.g. 500_INTERNAL_ERROR)
messageBrief description such as "Time-out" or "Something went wrong"

Example:

{
"errorCode": "500_INTERNAL_ERROR",
"message": "Something went wrong"
}
POST/api/sct-inst/v1/return/approvalApprove or Reject a Return

4️⃣ Resolution Approval​

Approval of Resolutions is used when a resolution message (ISO 20022 camt.029) is sent in response to a recall or investigation and requires an explicit decision.

Request Structure

❢  identifiers

The identifiers section provides references to the message that requires approval:

FieldTypeRequiredDescriptionConstraints
internalIdStringYesInternal identifier of the SCT_INST message to be processed. Must reference a previously created instruction, recall, return, or resolution message.1-36 chars, e.g. PAI1500002433134

❢  ApprovalDetails

The ApprovalDetails section specifies the action to be taken and optional rejection reasoning:

FieldTypeRequiredDescriptionConstraints
actionStringYesThe action to be performed on the message.Enum:
approve
reject
rejectReasonStringNoReason for rejection. Required only when action is reject.Max 512 chars, e.g. "Suspicious transaction pattern"
Response Structure
🟒 Success β€” HTTP 200

Approval or rejection was accepted by the system and its state updated. The HTTP 200 – OK response may include updated identifiers and/or a pain.002 status message.

This returns a response with the following structure:

For Successful Approval/Rejection with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00",
"DbtrAgt": {
"FinInstnId": {
// ... financial institution details
}
}
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "PNDG",
"StsRsnInf": [
// ... status reason information
]
},
"OrgnlPmtInfAndSts": [
// ... original payment information and status
]
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

For Simple Success Response:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"success": {
"status": "Success",
"transactionid": "PAI1500004121533"
}
}
πŸ”΄ Error β€” HTTP 400

In case of a validation or logical error (e.g. wrong state, missing fields), the API responds with the following structure for HTTP 400 – Bad Request errors:

Error with ISO Message:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"message": {
"Document": {
"CstmrPmtStsRpt": {
"GrpHdr": {
"MsgId": "PAI0500000018109",
"CreDtTm": "2025-04-30T17:30:29.587379623+02:00"
},
"OrgnlGrpInfAndSts": {
"OrgnlMsgId": "MSG-456312",
"OrgnlMsgNmId": "pain.001.01.09",
"OrgnlNbOfTxs": "1",
"OrgnlCtrlSum": 1006.87,
"GrpSts": "RJCT",
"StsRsnInf": [
// ... rejection reason information
]
}
}
}
},
"identifiers": {
"creditId": "PAI1500000018805",
"instructionId": "PAI1500000019002"
}
}

Timeout Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"error": {
"message": "Timeout while waiting for response"
}
}

Field Validation Error:

{
"header": {
"responseId": "603027ad-1047-43a3-b89b-03ff75fc8af9",
"originalRequestId": "ReqId-833583220015",
"responseTime": "2025-06-02T14:15:22Z"
},
"fields": [
{
"fieldMap": "/Document/CstmrCdtTrfInitn/PmtInf/0/CdtTrfTxInf/0/UltmtCdtr/Id/OrgId",
"reasonCode": "FF01",
"reasonText": "expected string, but got object"
}
]
}
🟑 Error β€” HTTP 500

Responses for HTTP 500 β€” Server Error errors are returned on unexpected server-side failures and contain:

GroupDescription
errorCodeApplication-level error identifier (e.g. 500_INTERNAL_ERROR)
messageBrief description such as "Time-out" or "Something went wrong"

Example:

{
"errorCode": "500_INTERNAL_ERROR",
"message": "Something went wrong"
}
POST/api/sct-inst/v1/resolution/approvalApprove or Reject a Resolution

Summary β€” Approving SCT Inst Messages​

All four approval endpoints (Instruction, Recall, Return, Resolution) implement the same Four-Eyes approval pattern:

identify the transaction β†’ decide (approve/reject) β†’ system validates, updates state, and logs.


Each endpoint has:

  • Its own URL and use case,
  • Possibly slightly different request fields or identifiers,
  • The same high-level response/HTTP status patterns.