Transaction Initiation

This section walks through how ZipRight allows users to initiate a new ZIP code verification transaction.


Step 1: Initiate Transaction


When the user reaches the final step on the order form wizard, and submits the ZIP code verification request, the user-interface interacts with the JavaScript API to create a new transaction on the users behalf:

...

// Order placement function
  const placeOrder = async () => {
    // Increment active step on new order wizard
    handleNext();

    // Create new transaction
    const proxy = await host;
    const transactionResponse = await proxy.createTransaction({
      request: {
        // Supported request type - defined in product configuration
        type: 'ZIP Code Validation',
        options: {
          // Custom transaction options
          customStringOption: 'test',
          customNumericOption: 100,
          customBooleanOption: true,
          customObjectOption: {
            customStringOption: 'test',
            customNumericOption: 100,
            customBooleanOption: true,
          },
        },
      },
    });
    
...

As illustrated in the snippet above - the JavaScript API's transaction.create method is being invoked when the user submits the verification request. This is encapsulated within the host objects createTransaction method call - you can see its implementation at:
.../epc-hello-world/user-interface/src/services/HostConnectionService/HostConnectionService.js

  • As defined in the transaction.create method interface - the method must receive a valid $.request.type as listed in your products configuration.

  • The method also optionally accepts an $.request.options object - this is a free form object that can contain any order specific options you may have collected from the user on the order form. For example, for a Credit integration, one option could be which bureaus to order a borrowers credit score from. In the case of a Verification of Income/Employment integration, one option could be how many days of income information to pull for a borrower. Of-course, you are free to model the $.request.options as you'd like - in the case of ZipRight, for simplicities sake, we are not collecting any order options from the user, but we do illustrate how options can be communicated to your transaction fulfillment workflow in the snippet above.


📘

Always Think API First!

As a best practice, design your $.request.options contract with an API first approach.

Your options contract should contain a minimal representation of the order options specific to your product and associated $.request.type. The contract should be clear, self-documenting, and easy for developers to read and reason about.

Remember, all integrations on EPC are automatically available to Encompass Lenders using Developer Connect - so a good data contract can play an important role in driving your integrations adoption!

❗️

The request options are not a container to exchange loan or PII user information. Please engage with the EPC support team if you feel like you are adding attributes to your options that should ideally be sourced from the loan file via our REST API, to promote data security and consistency between our systems. We can get the necessary data requirements added to your request data entitlements as applicable.


  • Another attribute a transaction request can contain is a collection of references to file attachments the user has uploaded from their local drive or selected from the host applications document repository - to be made available to your integration when processing the request. This information is to be encapsulated in the $.request.resources object. We don't illustrate the file attachment workflow in ZipRight - but you can read more about supporting this use case in the Document Management deep dive section.

Step 2: Query Transaction Processing Status


Once the transaction is successfully created - the Promise returned by the transaction.create method will resolve to an object containing the unique id for the transaction in the EPC platform. The ZipRight user-interface uses this transaction identifier to poll the ZipRight back-end for the latest status of the transaction - showing a waiting-state spinner while doing so.


📘

ZipRight has been purposefully developed as a simple and illustrative application - so that developers can quickly understand the core transactional workflows that comprise of an integration built on EPC ⚙️

The choice to implement the status query as a repetitive poll to the back-end was also made to keep things simple. In fact - for a production grade application - there are probably better and more scalable ways to achieve this functionality 💡

In fact - any communication between an integrations front and back-end is open to the integrators design. EPC imposes no restrictions on how communications external to its API are implemented. There are some best practices though, for certain workflows, that we do advise integrators to adopt. Read the deeper dive reference guides to learn more.


In the meanwhile - the ZipRight back-end should have received a transaction creation webhook also containing the unique id for the subject transaction - which it will record and track the status of as it makes progress in processing the associated request. We will dive into more detail on what the back-end does in its request processing in the next section on transaction fulfillment.

For now - here's how the ZipRight user-interface periodically checks on transaction status:

...

import StatusService from '../../services/StatusService/StatusService';

...

// Poll for status of transaction processing once created
    const transactionId = transactionResponse.id;
    const statusTracker = StatusService(transactionId);

    try {
      // Poll transaction status
      await statusTracker.pollStatus();
      
      // Once request processing is completed - update UI state
      setOrderStatus(1);

      // Wait a couple seconds before navigating to order details page
      await new Promise((resolve) => setTimeout(resolve, 2000));
      navigate(`details/${transactionId}`);
    } catch (err) {
      console.log(err);
    }

...

Once it receives the transaction status indicating the request has been completed - it navigates the user to the order details page - which renders just like we explained in the previous section. Voila - the order initiation workflow is now complete! 🎉


For clarity - you can see the implementation of the pollStatus method on the StatusService module here:

...

// Internal function that invokes the integrations back-end API repetitively
  // to access transaction processing status
  const _pollStatus = async (timeout = 300000, interval = 200) => {
    // Define when to stop polling
    const endTime = Number(new Date()) + timeout;

    // Execute determinator function
    const checkCondition = async (resolve, reject) => {
      // Get current status
      const currentResponse = await _getStatus();
      const currentStatus = currentResponse.status;
      
      if (currentStatus === 'REQUEST_COMPLETED') {
        resolve(currentResponse);
      } else if (Number(new Date()) < endTime) {
        // If the condition isn't met but the timeout hasn't elapsed, go again
        setTimeout(checkCondition, interval, resolve, reject);
      } else {
        // Didn't match and too much time, exit and reject
        reject(new Error(`Polling timed out!`));
      }
    };

    return new Promise(checkCondition);
  };

...