Constellation Digital Partners

Constellation Digital Partners

Constellation Digital Partners (CDP)

CDP is a digital platform marketed to credit unions where they can build and manage their entire digital user experience. CDP also works with fintechs, who build apps that run within the CDP experience called tiles. Fintech tiles inside of CDP have a variety of different functions, from wealth management to budgeting.

Most fintech applications use aggregation services like Yodlee, MX, or Plaid to securely gather financial data from third-party financial institutions (for example, credit card companies or other banks). FinGoal allows Constellation Digital Partners (CDP) users to aggregate financial data through Envestnet | Yodlee.

The Problem

Currently, developers using CDP are not able to aggregate third-party data from within the CDP experience. Instead, they need to integrate directly with the aggregation provider to pull data.

Most third-party aggregators embed their authentication forms directly onto webpages in the form of an iframe. Unfortunately, CDP does not currently allow developers to embed their own iframes within tiles, so the developers have had to find workarounds, in order to integrate third-party aggregation data.

Additionally, this implementation means each fintech tile has to:

  • Go through the costly process of developing their own aggregation portal
  • Require users to authenticate accounts, even those account were previously authorized within the credit union app.
  • Pay for the user's account aggregation on a per user or per account basis.

The user experience is confusing and tedious requiring them to link the same accounts multiple time. Redundant links for the same account is costly and give CDP less control and limited insight into third party aggregation data.

The Proposed Solution

FinGoal's aggregation service operates as a go-between for CDP and Yodlee that imposes a custom architecture meant to replicate multiple aggregations. FinGoal leverages existing experience for integrating Yodlee, and provides additional API routes to impose a multi-tenant system atop existing functionality. With this architecture, we:

  1. Let users authenticate each third-party application once and only once per credit union. Additional authorized tile applications can get permission from the credit union to access already aggregated data, ensuring that the user's data is stewarded appropriately.
    • Allow users to authenticate accounts only once for all tiles within the credit union.
    • Ensure appropriate
  2. Aggregate user data to a single source and prevent multiple different aggregation configurations.
  3. Enforce a single data model for developer ease.
  4. Front third-party data to the credit union and CDP for additional use cases
  5. Allow for the registration of multiple webhooks for developer clients
  6. Impose a custom tenant system for more granular access control in a large organization.

CDP Glossary

If you’re unfamiliar with CDP terminology, here are few terms to know.

Terms

NameDefinition
Connector
A package of Java that runs as non-frontend code within the CDP application.
Tile
A package of HTML and JavaScript that runs as an applet within the CDP wrapping application.
Aggregator
A connector that is expressly designed to integrate non-CDP data with the CDP database.

How to Implement LinkMoney on CDP

This guide is a generic guide for using LinkMoney on CDP. The steps for doing so are, broadly:

  1. Configuring a developer account for LinkMoney.
  2. Opening the LinkMoney tile with the correct parameters.
  3. Handling LinkMoney tile flow responses.
  4. Receiving data from LinkMoney.
  5. Sending data to LinkMoney.
  6. Troubleshooting.

CUFX Schemas

CDP resides just above a CUFX (Credit Union Financial Exchange) application layer. CUFX is an API that supplies basic functionality for Credit Unions to run their online resources. Because CDP uses and sits on top of CUFX core functionality, many of CDP's schemas for core data are derived from CUFX data. This section will map and describe several of the most important CUFX schemas, derived from the XSD files in the CUFX 3.2 Schemas, which are no longer publicly available documentation because the company that owns CUFX would rather people not know how to use it anymore.

Transactions
type: object
properties:
  transactionMessage: 
    type: object
    description: Transactions and associated account and user ids.
    properties: 
      messageContext: 
        type: object
        description: [guaranteed] Financial institution id.
        properties: 
          fiId: 
            type: string
      transactionFilter: 
        type: object
        description: [guaranteed] Account and User ids associated with transactions.
        properties: 
          accountIdList: 
            type: object
            properties: 
              accountId: 
                type: array
                description: [guaranteed] Account ids associated with transactions.
                items: 
                  type: string
          userIdList: 
            type: object
            properties: 
              userId: 
                type: array
                description: [guaranteed] User id associated with transactions.
                items: 
                  type: string
      transactionList: 
        type: object
        properties: 
          transaction: 
            type: array
            description: Array of all transactions.
            items: 
              type: object
              properties: 
                transactionId: 
                  type: string
                  description: [guaranteed] Unique id for transaction.
                accountId: 
                  type: string
                  description: [guaranteed] An accountid pointing to the ID of the user's account with their financial provider.
                type: 
                  type: string
                  description: Whether the transaction debited or credited the account.
                amount: 
                  type: object
                  properties: 
                    value: 
                      type: number
                      description: [guaranteed] Transaction amount.
                    currencyCode: 
                      type: string
                      description: [guaranteed] Currency Code
                description: 
                  type: string
                  description: [guaranteed] A simplified, parsed description of where the transaction occurred.
                dateTimePosted: 
                  type: string
                  description: [guaranteed] Date and time the transaction took place. 
                  format: date
                dateTimeEffective: 
                  type: string
                  description: Date and time the transaction took posted. 
                  format: date
                status: 
                  type: string
                  description: Status of the transaction post | pending.
                category: 
                  type: string
                  description: Broad category of transaction.
                source: 
                  type: string
                  description: System or delivery channel that originated the transaction.
Accounts
type: object
properties: 
  depositMessage: 
    depositFilter: 
      partyIdList: [guaranteed] Party id associated with transactions.
        description:  
        partyId: 
          - "[guaranteed] 12656"
      userIdList: 
				description: [guaranteed] User id associated with transactions.
        userId: 
          - "[guaranteed] 12656"
    depositList: 
      deposit: 
        - 
          accountId: "12656S0001"
						type: string
						description: Unique identifier for the account.
          accountNickName: ""
						type: string
						description: The name of the account, either assigned by the user or by the financial institution.
          actualBalance: 
						type: object
						properties:
	            currencyCode: "USD"
								type: string
								description: Currency Code
	            value: 6065.00
								type: number
								description: Running Balance
          availableBalance: 
            type: object
						properties:
	            currencyCode: "USD"
								type: string
								description: Currency Code
	            value: 6065.00
								type: number
								description: Available Balance
          customData: 
            valuePair: 
              - 
                name: "ProductCode"
                value: "0"
          description: "SAVINGS"
						type: string
						description: 
          dividendRate: "0.000"
						type: string
						description: Dividend rate.
          meta: 
            loanMeta: 
              maturityDate: "2021-05-30"
							type: string
							description: Date of maturity.
          openDate: "2005-11-09"
						type: string
						description: Date account was opened. 
          subType: "High yield"
						type: string
						description: Descriptive
          type: Savings
						type: string
						description: The subvariety of the account, if applicable.
    messageContext: 
      fiId: cdp-symxchange

Link Accounts on CDP

Constellation Digital Partners (CDP) is a platform that provides ready-made applications for Credit Unions to deploy. Through the CDP platform, Fintech developers can create and list applets that run within these Credit Union digital experiences. This means that credit union members can get access to all kinds of fintech tools directly within the context of their credit union application.

LinkMoney exists within the CDP experience as one such applet, called a tile. Other fintech tiles redirect to the LinkMoney Tile, which allows users link their external financial accounts. LinkMoney's APIs are also available to CDP tile and connector developers to improve the aggregation experience for developers platform-wide.

Invoking the Link Accounts Tile

In order to aggregate data through Link Accounts, invoke the Link Accounts Tile within CDP:

var callbackFunc = function(response) {
    if (response.success == false) {
        container.tile.ui.showMessage('Error', 'Error opening tile');
        consolelog('Error calling tile.opentile - ' + response.message);
    }
};
//To test in ADP you can retrieve the tilecode by going to Manage Projects -> Edit and finding the GUID in the url.
var tilecode = 'AAAAAAAA-AAAA-1AAA-8AAA-AAAAAAAAAAAA';
var tileversion = '1.1';
var opendata = {
  client_id: "YOUR LINK MONEY CLIENT_ID",
  client_secret: "YOUR LINK MONEY CLIENT_SECRET",
};
container.tile.opentile(tilecode, tileversion, callbackFunc, opendata);

From the tile, a user can see their existing accounts, add another account, refresh their balances, update an existing account, and delete an account.

Once the user chooses to add an account, they will be redirected to the Link Money Gateway. Upon linking an account, the Gateway will close and return the user to the Link Money Tile. Accounts and transactions will be aggregated, cleaned up and sent to the CDP Core where they will now return with the getTransactions and getAccounts Container API calls.

*If the data is not written to the core, service providers can call the Link Money connector.

LinkMoney Connector

LinkMoney's connectors are Spring Java applications that serve as access corridors between LinkMoney API and the LinkMoney tile internal to CDP. The connector is composed of a few core files:

Endpoints

The LinkMoney connector endpoints provide FinGoal, CDP, and other developers tools to interact with the LinkMoney API's datastores and routes.

Get Authentication Token
Get Authentication Token

Top Level Schemas

All routes on the LinkMoney connector require the connector JSON to contain four primary fields:

  • connectorParametersResponse
  • response
  • responseStatus
  • externalServicePayload

These fields are described more fully in the model tables below. Every request from tiles within an authentication CDP container - including the

- automatically have many of these fields populated through the container API connector functions.

Requests to the connector methods contain key user data, connector method invocation data, and other useful metadata to govern how the connector method should behave.

It is important to note that calls to the connector also contain a response and a responseStatus which are intentionally left blank. The connector will populate these parameters with the details of its response and respond to the tile with exactly the same schema that is described here. See the example request and example response for a concrete example of how this looks.

Payload

NameRequiredDescription
externalServicePayload
The data the tile sends to the connector, including tile metadata, user data, and the payload.
response
A string which will contain stringified JSON from the connector.
connectorParametersResponse
Parameters for governing Connector behavior.
responseStatus
Some information detailing the status of the connector's response.

connectorParametersResponse

NameRequiredDescription
connectorController
String
parameters
Contains a single array, valuePair, which can contain parameters build by the connector call.
method
Also contains a parameters field as described above, and an additional isValid boolean.

responseStatus

NameRequiredDescription
statusCode
The HTTP response code the connector sends will go here.
statusReason
A possible string reason why the request failed, if it did.
requiredFields
A String[] that indicates what, if any, required fields were exempted from the request.
statusDescription
A string description of the status.
status
A brief string description of the status.

externalServicePayload

NameRequiredDescription
userData
Contains all data for the authenticated CDP user.
requestType
Contains metadata for which connector the tile wants to invoke.
payload
Contains the tile's payload, if there is one.

requestType

NameRequiredDescription
connector
String name of the connector to be invoked.
method
String name of the connector method to be invoked.
version
String version of the connector to be invoked. For example, 1.1.

payload

NameRequiredDescription
valuePair
An array containing value-pairs that serve as invocation parameters for the connector method.

userData

NameRequiredDescription
memberId
String unique ID of the member.
userId
String unique ID of the user.
individualId
String unique ID of the individual.
middleName
The user's middle name or middle initial.
endUserNameKey
lastName
The user's last name.
fiId
String unique ID of the FI to which the user belongs.
emailAddress
The user's email address.
homePhone
The user's home phone number.
firstName
The user's first name.
mobilePhone
The user's mobile phone number.
workPhone
The user's work phone number.
mailingAddress
The user's mailing address details.

mailingAddress

NameRequiredDescription
zipCode
The string zip code the user lives in.
state
The two-character state code for the state the user lives in.
line2
The user's secondary address. For example, APT 301
line1
The user's primary address. For example, 123 MAIN ST
city
The city the user lives in.

Generic Example: Request JSON

{
    "externalServicePayload": {
        "requestType": {
            "connector": "FinGoalApplication",
            "version": "1.0",
            "method": "GetAuthenticationToken"
        },
        "payload": {
            "valuePair": []
        },
        "userData": {
            "userId": "abc12345-6789-abcd-abcd-09b2f99daf02",
            "firstName": "John",
            "middleName": "D",
            "lastName": "Smith",
            "emailAddress": "nope@noreply.com",
            "homePhone": "555-555-5555",
            "workPhone": "555-555-5555",
            "mobilePhone": "555-555-5555",
            "mailingAddress": {
                "line1": "123 MAIN ST",
                "line2": null,
                "city": "RALEIGH",
                "state": "NC",
                "zipCode": "90210"
            }
        }
    },
    "connectorParametersResponse": {
        "parameters": {
        },
        "method": {
            "parameters": {
                "valuePair": []
            },
            "isValid": true
        },
        "connectorController": ""
    },
    "response": "",
    "responseStatus": {
        "statusCode": "",
        "statusDescription": "",
        "status": "",
        "statusReason": "",
        "requiredFields": []
    }
}

Generic Example: Response JSON

See the Item Model for a full description of the schema.

{
    "externalServicePayload": {
        "requestType": {
            "connector": "FinGoalApplication",
            "version": "1.0",
            "method": "GetAuthenticationToken"
        },
        "payload": {
            "valuePair": []
        },
        "userData": {
            "memberId": null,
            "individualId": null,
            "fiId": null,
            "endUserNameKey": null,
            "userId": "abc12345-6789-abcd-abcd-09b2f99daf02",
            "firstName": "John",
            "middleName": "D",
            "lastName": "Smith",
            "emailAddress": "nope@noreply.com",
            "homePhone": "555-555-5555",
            "workPhone": "555-555-5555",
            "mobilePhone": "555-555-5555",
            "mailingAddress": {
                "line1": "123 MAIN ST",
                "line2": null,
                "city": "RALEIGH",
                "state": "NC",
                "zipCode": "90210"
            }
        }
    },
    "connectorParametersResponse": {
        "parameters": {
            "valuePair": []
        },
        "method": {
            "parameters": {
                "valuePair": []
            },
            "isValid": true
        },
        "connectorController": ""
    },
    "response": "{\"response\": {\"test-response\"}}",
    "responseStatus": {
        "statusCode": null,
        "statusDescription": null,
        "status": null,
        "statusReason": null,
        "requiredFields": []
    }
}

Retrieving Transactions

In order to retrieve transactions you can call the Link Money connector directly or review the Link Accounts API documentation to set up webhooks or make the calls externally. See data models for the response schema.

container.connectors.sendRequest(
    "LinkAccountsConnector",
    "1.3",
    "GetTransactions",
    {
        developerId: "YOUR LINK MONEY CLIENT_ID",
        dataType: "plaid", //optional can be any of plaid, cdp, yodlee, mx
        desiredData: "transaction",
    },
    (res) => {
        console.log("GetTranasctions response", res);
    }
);container.connectors.sendRequest(
    "LinkAccountsConnector",
    "1.3",
    "GetAccounts",
    {
        developerId: "YOUR LINK MONEY CLIENT_ID",
        dataType: "plaid", //optional can be any of plaid, cdp, yodlee, mx
        desiredData: "account",
    accountId: "accountId" //optional if you'd like a specific account
    },
    (res) => {
        console.log("GetAccounts response", res);
    }
);

Retrieving Accounts

In order to retrieve accounts you can call our connector directly or review the Link Accounts API documentation to set up webhooks or make the calls externally. See data models for the response schema.


container.connectors.sendRequest(
    "LinkAccountsConnector",
    "1.3",
    "GetAccounts",
    {
        developerId: "YOUR LINK MONEY CLIENT_ID",
        dataType: "plaid", //optional can be any of plaid, cdp, yodlee, mx
        desiredData: "account",
		    accountId: "accountId" //optional if you'd like a specific account
    },
    (res) => {
        console.log("GetAccounts response", res);
    }
);

LinkMoney Aggregator Connector

The LinkMoney Aggregator Connector is a specialized form of connector that periodically updates CDP core data with new information from accounts linked through LinkMoney. This third-party data is, during the process of saving it to the LinkMoney core, enriched and formatted as core data. Developers using CDP's core functions are then able to retrieve external account data without having to alter any core functionality.

Retrieving Link Accounts Gateway Metadata

To complete the CDP-specific flows described by the Link Money Gateway Calls documentation, the Link Accounts connector can pull the most recent link accounts events for a particular authenticated user.

This method is offered to developers who want to see which items and accounts were linked during the most recent linking session.

var requestParams = {}

container.connectors.sendRequest("LinkAccountsConnector", "1.1.0", "GetLinkDataFromGateway"

This returns an events JSON array in the connector response, that contains data on the nature and content of the most-recent link for the authenticated user. These events can either be errors encountered during the link, or successfully-linked new items. For example:

"events": [
	{
		"type": "error",
		"message": "The credentials you've entered are incorrect. Verify that CAPS LOCK is not on and that the desired financial institution was selected."
	}, 
	{
		"type": "success",
		"data": {
			"user_id": "testorg1:testuser1",
			"item_id": "13774750",
			"institution_id": "16441",
			"accounts": [ "19730080" ]
		}
	}
]

Additional Resources

CDP documentation access is restricted by CDP. To get access, you will need a FinGoal team member who has access to the CDP developers Slack channel to invite you to both the Slack channel and the CDP developer portal, and a CDP administrator will need to authorize the invitation. Once you have access to the CDP Slack channel, you may visit the CDP developer portal and sign into it via SSO with your CDP Developers Slack Credentials.

Reach out to support@fingoal.com to get an invite and get access to the CDP documentation.