Instant Payments Adapter Extension Tutorial

Instant Payments (IP) are a relatively new way of transferring money (in the United States). Rather than a three day delay through the existing Automated Clearing House (ACH) system, Instant Payments allow the near instantaneous moving and settling of funds. Other Peer to Peer solutions have existed for several years that to various extents ride these same rails, but at the banking institution level, IP is just getting started.

From the Caliper SDK perspective, we treat IP like any other adapter type. There are lots of tables involved in the database, but we do our best to abstract these away and give you a clean and easy interface to test out your integration. Let’s build an extension and test it out!

The InstantPayments adapter type is invoked through the UUX interface’s Payment Requests Page (more on setting this up below):

LandingPage Widget:

../../../_images/ip_uux.png

Instant Payments page:

../../../_images/ip_payment_request.png

We are going to create and register an extension such that sending a Payment Request (or a Credit Transfer) will hook into your code, letting us control where that IP data goes, and report back whether or not it was successful. Either way, we expect the UUX interface to update with the success/failure information.

Prerequisites

Important

As this is all quite new, the SDK sandbox stacks are not all set up to support this. If you are developing a realtimepayment integration and these prerequisites result in errors, before moving on to the Create the Extension step, please reach out to the Caliper SDK team and we can get you set up. Thanks for helping us harden our stacks!

Note

While Instant Payments (IP) is the generic name for this flow, an older name was Realtime Payments. As such, the tables in the database are prefixed with RTP

  1. First, we need to make sure IP is enabled in your test stack. This will seed the database with all the appropriate data to start your development. It will also enable IP for one or more groups. Here we’re going to enable it for the default groups, Retail Users and Commercial Users (groups 1 and 2 in this test database):

    $ q2 sandbox instant_payments enable
    
    Ensuring Adapter tables are seeded
    Ensuring all InstantPayments DataTypes are seeded in Q2_RTPDataType
    Ensuring there is a dummy vendor in Q2_RTPVendors for null state
    Ensuring all RequestTypes are seeded in Q2_RTPRequestTypes
    Setting system defaults
    Setting defaults per group
    Which groups would you like to enable for?
    
        1) [x] Retail Users
        2) [x] Commercial Users
        3) [ ] Merchant Verification
        4) [ ] Q2 Test Group - DO NOT DELETE
        5) [ ] Q2 Retail Default
        6) [ ] Q2 Retail ExternalTransfer
        7) [ ] Q2 Retail PositivePay
        8) [ ] Q2 Retail MobileCapture
    
    Select a number to toggle. 'a' for All. 'b' to set all to Blank. Leave empty to continue:
    Updating for group: 2
    Invalidating HQ
    
  2. Next, this type of adapter needs an additional internally created Q2 library called q2msg. We can configure that with the sandbox command, too:

    $ q2 sandbox q2msg generate_keys  # Ensure we can decode messages from HQ
    
  3. Finally, let’s ensure all the sql stored procedures for local testing are up to date:

    $ q2 setup_db
    

Note

All of these sql files are marked as dev only and will not work in a datacenter environment yet.

Create the Extension

Now that the prerequisites are out of the way, we can get working on your extension itself. Thankfully, there’s not much to it!

  1. Generate the boilerplate using the q2 create_extension command:

    $ q2 create_extension
    
    New Extension Name: PayMeNow
    What type of extension are you creating?
    
        1) Online (default)
        2) SSO (Third Party Integration)
        3) Ardent (API)
        4) Q2Console (Backoffice)
        5) Central (Legacy Backoffice)
        6) Adapter    <-------------
        7) Audit Action
        8) Custom Health Check
        9) Message Bus
        10) Caliper API Custom Endpoint
        11) Base Extension
    
    
    Please make a selection and press Return [1]: 6
    Adapter
    Select adapter type to generate
    
        1) Account Details
        2) Authentication Token
        3) Check Image
        4) Domestic Wire
        5) Deposit Item Image
        6) FX Rate
        7) Instant Payments  <--------
        8) International Wire
        9) Remote Deposit
        10) Statement Image
    
  2. Register the active adapter for instant payments in the stack:

    $ q2 install PayMeNow
    
  3. We currently support two types of Instant Payment calls: RequestForPayment and CreditTransfer.

    • RequestForPayment: Requesting money from another entity

    • CreditTransfer: Sending money to another entity

    By default, your extension is generated with a generic “successful” response to each type:

    async def handle_rtp_request(self, request: RequestForPaymentRequest) -> InstantPaymentsResponse:
        """Using the information provided in `request` param, return a InstantPaymentsResponse"""
        success = True
        external_id = '123P'
        return InstantPaymentsResponse(success, external_id)
    
    async def handle_credit_transfer_request(self, request: CreditTransferRequest) -> CreditTransferResponse:
        """Using the information provided in `request` param, return a CreditTransferResponse"""
        success = True
        external_id = '456C'
        return CreditTransferResponse(success, external_id)
    

    There’s no need to change that for the moment. Let’s see how it works in the next step.

Testing the Extension

From the code above, we should be see a successful flow of either request type right away, and we’ll know it worked based on the external_id that will show up later in the process. ‘123P’ for RealtimePayment or ‘456C’ for CreditTransfer.

  1. Let’s try it out! Boot up your server:

    $ q2 run
    
  2. Log into UUX (with the user commercial0 if you followed the above steps). Navigate to the UUX Payment Request page and fill in some details:

    ../../../_images/ip_payment_request_with_details.png
  3. After you click Approve (or Draft), you should see logs in your locally running server. Here’s an example:

    2024-04-15T19:38:18.886 extension.PayMeNow/requestforpayment INFO     Q2     aa421bc216414b29a3055f45b2187741 RequestForPayment route
    2024-04-15T19:38:18.886 extension.PayMeNow/requestforpayment INFO     Q2     aa421bc216414b29a3055f45b2187741 RealtimePaymentRequest(generated_transaction_id='10002', user_id=3, customer_id=3
    , debtor=Q2Entity(name='Jane Doe', organization={}, account_number='12435', agent='022222222'), amount=1.0, currency='USD', condition={}, creditor=OtherParty(name='Commercial Customer', addre
    ss={'address_1': '13785 Research Blvd', 'address_2': 'Suite 150', 'city': 'Austin', 'state': '94730', 'zipcode': 'TX', 'address_type': 'Home', 'country': 'USA', 'province': '', 'additional_de
    tails': {}}, email='noreply@q2ebanking.com', account_number='S00'), expiry=None)
    2024-04-15T19:38:18.887 tornado.access  INFO     200 aa421bc216414b29a3055f45b2187741 POST /PayMeNow/requestforpayment (::1) 25.72ms
    
  4. You will also see a confirmation of the transfer in the Activity Center page:

    ../../../_images/activity_center.png
  5. Try the same thing for CreditTransfer:

    ../../../_images/ip_credit_transfer_request_with_details.png

Summary

And that’s it! Try playing around with the response. For instance, if you set the Response’s success boolean to False, how does that affect the result on the Activity Center page? Remember, all we’ve done with this extension is let the UUX frontend and database know we moved the money successfully. What is still up to you is actually doing the work! Using the same tools as we’ve seen in other tutorials such as q2_requests, caching, and logging, the next step is to integrate with your payment provider. Have fun!