Integration as a Payer DFSP

The following diagrams illustrate how a Payer DFSP interacts with Payment Manager and the Mojaloop Switch at the level of API calls.

api interfaces payer side

The simplified API between the DFSP backend and the Core Connector is a synchronous HTTP API (Payment Manager OSS API).

The API between the Core Connector and the Mojaloop Connector is also a synchronous HTTP API.

The interface between the Mojaloop Connector and the Mojaloop Switch is the asynchronous Mojaloop FSPIOP API.

Single-stage transfer

When a peer-to-peer (P2P) transfer (POST /sendmoney) happens in a single stage, the party lookup, quotes, and transfers requests all happen in a single step as illustrated in the sequence flow below:

p2p e2e detailed single stage
Figure 1. Peer-to-peer transfer (single-stage transfer)

To simplify the transfer flow and perform the transfer in a single combined step as shown in the diagram, configure the following environment variables in Mojaloop Connector:

  • Set AUTO_ACCEPT_PARTY=true.

  • Set AUTO_ACCEPT_QUOTES=true.

Example POST /sendmoney request

The following example shows a POST /sendmoney request (Step 2 in the diagram above).

POST /sendmoney
Content-Type: application/json
Accept: application/json

{
  "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
  "from": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "123456789",
    "displayName": "Antoine Dujardin",
    "firstName": "Antoine",
    "middleName": "Paul",
    "lastName": "Dujardin",
    "fspId": "walletABC"
  },
  "to": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "987654321"
  },
  "amountType": "SEND",
  "currency": "EUR",
  "amount": "50",
  "transactionType": "TRANSFER",
  "note": "from Antoine"
}

Example error responses to POST /sendmoney

The following example shows a response to a POST /sendmoney request when the request fails due to the Payee not being found (Step 22 in the diagram above).

For a detailed list of Mojaloop error codes and their description, see API Definition v1.1 (Open API for FSP Interoperability Specification).
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "3204",
  "message": "Got an error response resolving party: {
    errorInformation: { errorCode: '3204', errorDescription: 'Party not found' }
    }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "3204",
          "errorDescription": "Party not found"
        }
      }
    }
  }
}

The following example shows a response to a POST /sendmoney request when the request fails due to an internal server error when the quote is being created (Step 39 in the diagram above).

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "2001",
  "message": "Got an error response: {
  errorInformation: {
  errorCode: '2001',
  errorDescription: 'Internal server error'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "2001",
          "errorDescription": "Internal server error"
        }
      }
    }
  }
}

The following example shows a response to a POST /sendmoney request when the request fails due to the Payer not having sufficient funds (Step 52 in the diagram above).

The Net Debit Cap (NDC) check that the Mojaloop Switch performs serves to ensure that the Payer DFSP always has enough liquidity to cover their outgoing transfers. The NDC is a limit or a cap placed on a DFSP’s funds available for transacting. It represents the maximum amount of money that the DFSP can owe to other DFSPs. For each transfer request, the Switch checks whether or not executing the transfer would result in a breach of the NDC. If yes, the Switch blocks the transfer.

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "4001",
  "message": "Got an error response preparing transfer: {
  errorInformation: {
  errorCode: '4001',
  errorDescription: 'Payer FSP insufficient liquidity'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
    "quoteResponse": {
      "transferAmount": {
        "currency": "EUR",
        "amount": "50"
      },
      "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
      },
      "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
      },
      "expiration": "2021-06-15T13:31:11.500Z",
      "geoCode": {
        "latitude": "43.6047",
        "longitude": "1.4442"
      },
      "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
      "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
    },
    "quoteResponseSource": "walletXYZ",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "4001",
          "errorDescription": "Payer FSP insufficient liquidity"
        }
      }
    }
  }
}

The following example shows a response to a POST /sendmoney request (Step 77 in the diagram above) when the transfer fails expiry validation by the Switch (in Step 73, the Switch validates the fulfilment returned by the Payee DFSP and checks the expiry timestamp on the transfer).

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "3302",
  "message": "Got an error response fulfilling transfer: {
  errorInformation: {
  errorCode: '3302',
  errorDescription: 'Quote expired'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
    "quoteResponse": {
      "transferAmount": {
        "currency": "EUR",
        "amount": "50"
      },
      "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
      },
      "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
      },
      "expiration": "2021-06-15T13:31:11.500Z",
      "geoCode": {
        "latitude": "43.6047",
        "longitude": "1.4442"
      },
      "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
      "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
    },
    "quoteResponseSource": "walletXYZ",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "3302",
          "errorDescription": "Quote expired"
        }
      }
    }
  }
}

Example success response to POST /sendmoney

The following example shows a response to a POST /sendmoney request when the request is successful (Step 86 in the diagram above).

HTTP/1.1 200 OK
Content-Type: application/json

{
  "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
  "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
  "from": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "123456789",
    "displayName": "Antoine Dujardin",
    "firstName": "Antoine",
    "middleName": "Paul",
    "lastName": "Dujardin",
    "fspId": "walletABC"
  },
  "to": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "987654321",
    "displayName": "Aamir Fakhir",
    "firstName": "Aamir",
    "middleName": "Abdel",
    "lastName": "Fakhir",
    "fspId": "walletXYZ"
  },
  "amountType": "SEND",
  "currency": "EUR",
  "amount": "50",
  "transactionType": "TRANSFER",
  "note": "from Antoine",
  "currentState": "COMPLETED",
  "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
  "quoteResponse": {
    "transferAmount": {
      "currency": "EUR",
      "amount": "50"
    },
    "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
    },
    "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
    },
    "expiration": "2021-06-15T13:31:11.500Z",
    "geoCode": {
      "latitude": "43.6047",
      "longitude": "1.4442"
    },
    "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
    "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
  },
  "quoteResponseSource": "walletXYZ",
  "fulfil": {
    "fulfilment": "ZhrKmchS4bCpaGIcu5fuLOsIFDZqTpJeYf4Q9HOYF0c",
    "completedTimestamp": "2021-06-15T13:30:19.920Z",
    "transferState": "COMMITTED"
  }
}

Multi-stage transfer

You have the option to not automatically accept the returned party lookup and/or quote response and halt the transfer flow to examine party/quote information. For this, configure the following environment variables in Mojaloop Connector:

  • If you want to examine the returned party information, set AUTO_ACCEPT_PARTY=false.

  • If you want to examine the returned quote, set AUTO_ACCEPT_QUOTES=false.

After examining the party/quote, a further confirmation call is required to progress the transfer to the next stage:

  • To resume after party lookup, send PUT /sendmoney/{transferId} with "acceptParty" set to true in the request body.

  • To resume after a quote response is received, send PUT /sendmoney/{transferId} with "acceptQuote" set to true in the request body.

You can combine AUTO_ACCEPT_PARTY and AUTO_ACCEPT_QUOTES settings any way you want. You can choose to stop the transfer flow only after receiving party information, or only after receiving quote information, or after both.

In the example sequence flow shown below, the peer-to-peer (P2P) transfer flow (POST /sendmoney) happens in three stages (that is, the transfer flow stops after both party lookup and quoting):

p2p e2e detailed multi stage
Figure 2. Peer-to-peer transfer (multi-stage transfer)

Example POST /sendmoney request

See the example above shown for single-stage transfers (Step 2 in the diagram above).

Example error response to POST /sendmoney

In the following example (Step 22 in the diagram above) the request fails due to the Payee party not being found.

For a detailed list of Mojaloop error codes and their description, see API Definition v1.1 (Open API for FSP Interoperability Specification).
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "3204",
  "message": "Got an error response resolving party: {
    errorInformation: { errorCode: '3204', errorDescription: 'Party not found' }
    }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "3204",
          "errorDescription": "Party not found"
        }
      }
    }
  }
}

Example success response to POST /sendmoney

The following example shows a response to a POST /sendmoney request (Step 29 in the diagram above) when:

  • the request is successful, and

  • the transfer flow is set to halt after the party lookup stage (AUTO_ACCEPT_PARTY=false)

HTTP/1.1 200 OK
Content-Type: application/json

{
  "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
  "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
  "from": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "123456789",
    "displayName": "Antoine Dujardin",
    "firstName": "Antoine",
    "middleName": "Paul",
    "lastName": "Dujardin",
    "fspId": "walletABC"
  },
  "to": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "987654321",
    "displayName": "Aamir Fakhir",
    "firstName": "Aamir",
    "middleName": "Abdel",
    "lastName": "Fakhir",
    "fspId": "walletXYZ"
  },
  "amountType": "SEND",
  "currency": "EUR",
  "amount": "50",
  "transactionType": "TRANSFER",
  "note": "from Antoine",
  "currentState": "WAITING_FOR_PARTY_ACCEPTANCE"
}

Example PUT /sendmoney/{transferId} request (accepting the party)

The following example shows a PUT /sendmoney/{transferId} request sent to resume the transfer flow after the party lookup stage (Step 34 in the diagram above).

PUT /sendmoney/85feac2f-39b2-491b-817e-4a03203d4f14 HTTP/1.1
Content-Type: application/json

{
  "acceptParty": true
}

Example error response to PUT /sendmoney/{transferId} ("acceptParty": true)

The following example shows a response to a PUT /sendmoney/{transferId} ("acceptParty": true) request when the request fails due to the quote request failing (Step 45 in the diagram above).

For a detailed list of Mojaloop error codes and their description, see API Definition v1.1 (Open API for FSP Interoperability Specification).
HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "2001",
  "message": "Got an error response: {
  errorInformation: {
  errorCode: '2001',
  errorDescription: 'Internal server error'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "2001",
          "errorDescription": "Internal server error"
        }
      }
    }
  }
}

Example success response to PUT /sendmoney/{transferId} ("acceptParty": true)

The following example shows a response to a PUT /sendmoney/{transferId} request (Step 53 in the diagram above) when:

  • the request is successful, and

  • it is a response to an "acceptParty": true request and quote acceptance still needs to happen

HTTP/1.1 200 OK
Content-Type: application/json

{
  "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
  "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
  "from": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "123456789",
    "displayName": "Antoine Dujardin",
    "firstName": "Antoine",
    "middleName": "Paul",
    "lastName": "Dujardin",
    "fspId": "walletABC"
  },
  "to": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "987654321",
    "displayName": "Aamir Fakhir",
    "firstName": "Aamir",
    "middleName": "Abdel",
    "lastName": "Fakhir",
    "fspId": "walletXYZ"
  },
  "amountType": "SEND",
  "currency": "EUR",
  "amount": "50",
  "transactionType": "TRANSFER",
  "note": "from Antoine",
  "currentState": "WAITING_FOR_QUOTE_ACCEPTANCE",
  "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
    "quoteResponse": {
      "transferAmount": {
        "currency": "EUR",
        "amount": "50"
      },
      "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
      },
      "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
      },
      "expiration": "2021-06-15T13:31:11.500Z",
      "geoCode": {
        "latitude": "43.6047",
        "longitude": "1.4442"
      },
      "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
      "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
    },
    "quoteResponseSource": "walletXYZ"
}

Example PUT /sendmoney/{transferId} request (accepting the quote)

The following example shows a PUT /sendmoney/{transferId} request sent to resume the transfer flow after the quote stage (Step 59 in the diagram above).

PUT /sendmoney/85feac2f-39b2-491b-817e-4a03203d4f14 HTTP/1.1
Content-Type: application/json

{
  "acceptQuote": true
}

Example error response to PUT /sendmoney/{transferId} ("acceptQuote": true)

The following example shows a response to a PUT /sendmoney/{transferId} ("acceptQuote": true) request when the request fails due to the Payer not having sufficient funds (Step 65 in the diagram above).

The Net Debit Cap (NDC) check that the Mojaloop Switch performs serves to ensure that the Payer DFSP always has enough liquidity to cover their outgoing transfers. The NDC is a limit or a cap placed on a DFSP’s funds available for transacting. It represents the maximum amount of money that the DFSP can owe to other DFSPs. For each transfer request, the Switch checks whether or not executing the transfer would result in a breach of the NDC. If yes, the Switch blocks the transfer.

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "4001",
  "message": "Got an error response preparing transfer: {
  errorInformation: {
  errorCode: '4001',
  errorDescription: 'Payer FSP insufficient liquidity'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
    "quoteResponse": {
      "transferAmount": {
        "currency": "EUR",
        "amount": "50"
      },
      "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
      },
      "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
      },
      "expiration": "2021-06-15T13:31:11.500Z",
      "geoCode": {
        "latitude": "43.6047",
        "longitude": "1.4442"
      },
      "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
      "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
    },
    "quoteResponseSource": "walletXYZ",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "4001",
          "errorDescription": "Payer FSP insufficient liquidity"
        }
      }
    }
  }
}

The following example shows a response to a PUT /sendmoney/{transferId} ("acceptQuote": true) request (Step 90 in the diagram above) when the transfer fails expiry validation by the Switch (in Step 86, the Switch validates the fulfilment returned by the Payee DFSP and checks the expiry timestamp on the transfer).

HTTP/1.1 500 Internal Server Error
Content-Type: application/json

{
  "statusCode": "3302",
  "message": "Got an error response fulfilling transfer: {
  errorInformation: {
  errorCode: '3302',
  errorDescription: 'Quote expired'
  }
  }",
  "transferState": {
    "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
    "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
    "from": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "123456789",
      "displayName": "Antoine Dujardin",
      "firstName": "Antoine",
      "middleName": "Paul",
      "lastName": "Dujardin",
      "fspId": "walletABC"
    },
    "to": {
      "type": "CONSUMER",
      "idType": "MSISDN",
      "idValue": "987654321",
      "displayName": "Aamir Fakhir",
      "firstName": "Aamir",
      "middleName": "Abdel",
      "lastName": "Fakhir",
      "fspId": "walletXYZ"
    },
    "amountType": "SEND",
    "currency": "EUR",
    "amount": "50",
    "transactionType": "TRANSFER",
    "note": "from Antoine",
    "currentState": "ERROR_OCCURRED",
    "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
    "quoteResponse": {
      "transferAmount": {
        "currency": "EUR",
        "amount": "50"
      },
      "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
      },
      "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
      },
      "expiration": "2021-06-15T13:31:11.500Z",
      "geoCode": {
        "latitude": "43.6047",
        "longitude": "1.4442"
      },
      "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
      "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
    },
    "quoteResponseSource": "walletXYZ",
    "lastError": {
      "httpStatusCode": 500,
      "mojaloopError": {
        "errorInformation": {
          "errorCode": "3302",
          "errorDescription": "Quote expired"
        }
      }
    }
  }
}

Example success response to PUT /sendmoney/{transferId}

The following example shows a response to a PUT /sendmoney/{transferId} request (Step 99 in the diagram above) when:

  • the request is successful (all checks and validations have been successful), and

  • the response is:

    • either a response to an "acceptQuote": true request

    • or a response to an "acceptParty": true request where AUTO_ACCEPT_QUOTES=true has been set, that is, quote acceptance has happened automatically

HTTP/1.1 200 OK
Content-Type: application/json

{
  "transferId": "85feac2f-39b2-491b-817e-4a03203d4f14",
  "homeTransactionId": "53979be2-3bfe-45aa-ade7-92ea4ce4e74e",
  "from": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "123456789",
    "displayName": "Antoine Dujardin",
    "firstName": "Antoine",
    "middleName": "Paul",
    "lastName": "Dujardin",
    "fspId": "walletABC"
  },
  "to": {
    "type": "CONSUMER",
    "idType": "MSISDN",
    "idValue": "987654321",
    "displayName": "Aamir Fakhir",
    "firstName": "Aamir",
    "middleName": "Abdel",
    "lastName": "Fakhir",
    "fspId": "walletXYZ"
  },
  "amountType": "SEND",
  "currency": "EUR",
  "amount": "50",
  "transactionType": "TRANSFER",
  "note": "from Antoine",
  "currentState": "COMPLETED",
  "quoteId": "7c23e80c-d078-4077-8263-2c047876fcf6",
  "quoteResponse": {
    "transferAmount": {
      "currency": "EUR",
      "amount": "50"
    },
    "payeeFspFee": {
        "amount": "0",
        "currency": "EUR"
    },
    "payeeFspCommission": {
        "amount": "0",
        "currency": "EUR"
    },
    "expiration": "2021-06-15T13:31:11.500Z",
    "geoCode": {
      "latitude": "43.6047",
      "longitude": "1.4442"
    },
    "ilpPacket": "AYIDUgAAAAAAAAPoIWcucGF5ZWVmc3AuYWNjb3VudF9pZC4xNzAzOTgxMTkwN4IDJGV5SjBjbUZ1YzJGamRHbHZia2xrSWpvaU4ySTRNbUZoT0RrdE0yTTNOeTAwWmpFNUxXSTFPRFl0TlRFNU5USXlaVEJtT0RNN
Ulpd2ljWFZ2ZEdWSlpDSTZJamxpTWpWbFlqYzRMV05rWVRrdE5HUXhaaTFoWkRVM0xXRmlOV1pqWVdObU1EaGtaU0lzSW5CaGVXVmxJanA3SW5CaGNuUjVTV1JKYm1adklqcDdJbkJoY25SNVNXUlVlWEJsSWpvaVFVTkRUMVZPVkY5SlJDSXNJbkJoY25SNVNXUmxiblJwWm1sbGN
pSTZJakUzTURNNU9ERXhPVEEzSWl3aVpuTndTV1FpT2lKd1lYbGxaV1p6Y0NKOUxDSndaWEp6YjI1aGJFbHVabThpT25zaVkyOXRjR3hsZUU1aGJXVWlPbnNpWm1seWMzUk9ZVzFsSWpvaVUybHRSbWx5YzNRaUxDSnRhV1JrYkdWT1lXMWxJam9pVTJsdFRXbGtaR3hsSWl3aWJHR
npkRTVoYldVaU9pSlRhVzFNWVhOMEluMHNJbVJoZEdWUFprSnBjblJvSWpvaU1qQXhNQzB4TUMweE1DSjlmU3dpY0dGNVpYSWlPbnNpY0dGeWRIbEpaRWx1Wm04aU9uc2ljR0Z5ZEhsSlpGUjVjR1VpT2lKQlEwTlBWVTVVWDBsRUlpd2ljR0Z5ZEhsSlpHVnVkR2xtYVdWeUlqb2l
NVGM0TlRVMU1ERTVNVFFpTENKbWMzQkpaQ0k2SW5CaGVXVnlabk53SW4wc0ltNWhiV1VpT2lKUVlYbGxja1pwY25OMElGQmhlV1Z5VEdGemRDSjlMQ0poYlc5MWJuUWlPbnNpWVcxdmRXNTBJam9pTVRBaUxDSmpkWEp5Wlc1amVTSTZJbFZUUkNKOUxDSjBjbUZ1YzJGamRHbHZib
FI1Y0dVaU9uc2ljMk5sYm1GeWFXOGlPaUpVVWtGT1UwWkZVaUlzSW1sdWFYUnBZWFJ2Y2lJNklsQkJXVVZTSWl3aWFXNXBkR2xoZEc5eVZIbHdaU0k2SWtOUFRsTlZUVVZTSW4xOQA",
    "condition": "FravH43bz3pO3AOwuaC5wo26Gv3p_rQiASsREK_ueoQ"
  },
  "quoteResponseSource": "walletXYZ",
  "fulfil": {
    "fulfilment": "ZhrKmchS4bCpaGIcu5fuLOsIFDZqTpJeYf4Q9HOYF0c",
    "completedTimestamp": "2021-06-15T13:30:19.920Z",
    "transferState": "COMMITTED"
  }
}