Quickstart

The Quickstart covers the entire workflow from setting up Truv Bridge to retrieving data with the API.

Introduction

Truv lets you connect to your users to collect data from financial and payroll providers. Get started with Truv and follow the sections below.

📘

Tip

For no-code solutions, use the Truv Postman Collection to get started with Truv's API.

View the complete workflow for getting started with Truv when you clone the Quickstart app. The repository covers each step from initializing Truv Bridge to retrieving data using the API.

Prerequisites

You’ll need the following to get setup with Truv.

Sign up for Truv through the Dashboard and collect your API keys. With those values, you can start making requests with the API.

Find your API keys under the Development section of your dashboard. Find examples of client_id and access_key or Access secret values below.

ValueDescriptionExample
client_idPrivate identifier for your teamdd21ca23c12142b6a0970b1e0afedf16
access_keyPrivate key, one for each of the three environmentssandbox-a57b3109f1f4a8b3f2ebbc1c526950f1795464af

Get the Client ID and Access secret by clicking the Development -> API keys menu item in the Dashboard. Each environment has its own access_key.

🚧

Warning

The Client ID and Access key provide access to sensitive information. Save these values and store them in a secure and private location.

Environments

View the descriptions for sandbox, development, and production environments below.

  • Sandbox - For development with test credentials, unlimited requests and free
  • Development - For testing integration with live credentials, includes 50 free Successful Tasks
  • Production - For your production environment, all successful Tasks are billed

📘

Tip

Contact [email protected] for any support throughout all steps in the Quickstart.

Configuring your app

When you have your API keys, you can run the Quickstart from Truv's GitHub on your local machine. Truv's GitHub page has examples from the these languages as well.

For mobile platforms, use the Quickstart apps for iOS and Android.

Instructions

The code instructions below guide you through the process on your local machine. It covers cloning the Quickstart repository, customizing the .env file with your Truv Client ID and Access Secret, and then building and running the app.

# Clone the Quickstart repository
git clone https://github.com/truvhq/quickstart.git

# Open Quickstart
cd quickstart

# Create .env file 
make env

# Update the values in .env file by adding in your Client ID and Sandbox Access key. 
# API_CLIENT_ID=<Your Client ID here>
# API_SECRET=<Your Access key here>

# Also, in .env uncomment the line with API_PRODUCT_TYPE that you want to use
# API_PRODUCT_TYPE=employment
# API_PRODUCT_TYPE=income
# API_PRODUCT_TYPE=deposit_switch
# API_PRODUCT_TYPE=pll
# API_PRODUCT_TYPE=admin

# Run the make script for your coding language
make python_local
# Clone the Quickstart repository
git clone https://github.com/citadelid/quickstart.git

# Open Quickstart in your coding language
cd quickstart/python

# Copy the .env.example file to a new file in the same directory and name it .env. 
cp .env.example .env

# Update the values adding in the your Client ID and Sandbox Access key. 
#API_CLIENT_ID=<Your Client ID here>
#API_SECRET=<Your Access key here>
# Uncomment the line with API_PRODUCT_TYPE that you want to use
#API_PRODUCT_TYPE=employment

#Run the make script for your coding language
make python_docker
/*
Clone the Quickstart repository:
git clone https://github.com/truvhq/quickstart-ios.git

Open Quickstart:
cd quickstart-ios

Create constants file:
touch truv-quickstart/Constants.swift
*/
import Foundation

var TruvClientID = "<client_id>"
var TruvClientSecret = "<access_key>"
var TruvAPIUrl = "https://prod.truv.com/v1/"
var TruvProductType = "<employment or income>"

/*
Open the project in XCode and run the app
*/
/*
Clone the Quickstart repository:
git clone https://github.com/truvhq/quickstart-android.git

Open Quickstart:
cd quickstart-android

Create constants file:
touch local.properties
*/

truvClientId="<client_id>"
truvSecret="<access_key>"
truvApiUrl="https://prod.truv.com/v1/"
truvProductType="<employment or income>"

/*
Open the project in Android Studio and run the app
*/

Your app will be running at http://localhost:5000. iOS and Android mobile apps launch in Xcode or Android Studio, respectively.

Creating your first Link

The Truv Link is a login attempt at a payroll provider, work account or financial institution. The Truv API requests interact with Links to exchange end-user credentials for access to payroll provider information. Links contain the required context to represent the end-user.

Users can have a single or multiple accounts with different providers. Links act as the connection between a user’s payroll provider and employer.

For users, the number of links is related to the number of payroll providers using that login information. The table below has examples of users, employers, payrolls, and Link totals.

UserEmployer & payroll providerNumber of Links
John Doe- Company A, provider A
- Company B, provider A
1
Jane Smith- Company C, provider B
- Company D, provider C
2

Adding Link to app in sandbox environment

After you’ve run your Quickstart app, add your first Link in the sandbox. When your Quickstart app is open, click Connect and follow the instructions in Truv Bridge.

Use the sandbox credentials below for simulating a successful login. The sandbox environment allows you to login with multiple credentials. These provide various scenarios for testing data.

  • username - goodlogin
  • password - goodpassword
  • For multi-factor authentication prompts - 12345

To view the data from Truv, click Done at the end of the Bridge session.

Truv process summary

The Truv workflow covers your application, Truv Bridge, your server, and the Truv API. View the steps below to learn more about the communication between each component.

  1. The application uses the bridge_token to make a request to your server.
  2. Your server makes a POST request with the user information to the Truv API.
  3. After the API processes the exchange, your application then prompts the user to connect payroll information in Truv Bridge.
  4. When successful, Truv Bridge returns the required credentials to your application.
  5. During this step, your server monitors webhook events from the Truv API.
  6. With the public_token, your application makes an exchange to your server and the Truv API for access.
  7. After your server collects the appropriate credentials, it can complete the request to get data from the Truv API.

Summary of sequence diagram

The chart below is an overview of the steps in the process.

Requesting bridge_token value

The bridge_token is the first value required to authenticate your app with Truv Bridge. This is a temporary single-use token for a user. When you create a new user, make a request to the Create a bridge token endpoint for the bridge_token value.

You can also pass environment variables from the Quickstart configuration as parameters. This helps you streamline the experience for your users with auto-populating or pre-filling information.

def create_user(self, **kwargs) -> dict:
    logging.info("TRUV: Requesting new user from https://prod.truv.com/v1/users/")
    payload = {
        "external_user_id": f"qs-{uuid4().hex}",
        "first_name": "John",
        "last_name": "Johnson",
        "email": "[email protected]",
        **kwargs,
    }
    return self.post("users/", json=payload)

def create_user_bridge_token(self, user_id: str) -> dict:
    logging.info(
      	"TRUV: Requesting user bridge token from https://prod.truv.com/v1/users/{user_id}/tokens"
    )
    logging.info("TRUV: User ID - %s", user_id)

    payload = {
        "product_type": self.product_type,
        "tracking_info": "1338-0111-A",
    }

    if self.product_type in ["deposit_switch", "pll"]:
        payload["account"] = {
            "account_number": "16002600",
            "account_type": "checking",
            "routing_number": "12345678",
            "bank_name": "Example Bank",
        }

        if self.product_type == "pll":
            payload["account"].update(
              {
                	"deposit_type": "amount",
                	"deposit_value": "100",
              }
            )
		return self.post(f"users/{user_id}/tokens/", json=payload)

const createUser = async () => {
  console.log('TRUV: Requesting a user from https://prod.truv.com/v1/users/');
  const bodyObj = {
    external_user_id: `qs-${uuidv4()}`,
    first_name: 'John',
    last_name: 'Johnson',
    email: '[email protected]',
  };
  const body = JSON.stringify(bodyObj);

  const responseBody = await sendRequest('users/', { body });
  return responseBody;
};


const createUserBridgeToken = async (user_id) => {
  console.log('TRUV: Requesting user bridge token from https://prod.truv.com/v1/users/{user_id}/tokens');
  console.log(`TRUV: User ID - ${user_id}`);

  const bodyObj = {
    product_type: API_PRODUCT_TYPE,
    client_name: 'Truv Quickstart',
    tracking_info: '1338-0111-A',
  };

  if (API_PRODUCT_TYPE === 'pll' || API_PRODUCT_TYPE === 'deposit_switch') {
    bodyObj.account = {
      account_number: '16002600',
      account_type: 'checking',
      routing_number: '123456789',
      bank_name: 'TD Bank',
    };

    if (API_PRODUCT_TYPE === 'pll') {
      bodyObj.account = { ...bodyObj.account, deposit_type: 'amount', deposit_value: '100' };
    }
  }

  const body = JSON.stringify(bodyObj);

  const responseBody = await sendRequest(`users/${user_id}/tokens/`, { body });
  return responseBody;
};
func createUser() (string, error) {
	log.Println("TRUV: Requesting new user from https://prod.truv.com/v1/users/")
	uniqueNumber := time.Now().UnixNano() / (1 << 22)
	userRequest := UserRequest{
		ExternalUserId: fmt.Sprintf("qs-%d", uniqueNumber),
		FirstName:      "John",
		LastName:       "Johnson",
		Email:          "[email protected]",
	}
	userJson, _ := json.Marshal(userRequest)
	request, err := getRequest("users/", "POST", userJson)
	if err != nil {
		return "", err
	}
	client := &http.Client{}
	res, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer res.Body.Close()

	user := UserResponse{}
	err = json.NewDecoder(res.Body).Decode(&user)

	return user.UserId, nil
}


func createUserBridgeToken(userId string) (string, error) {
	log.Println("TRUV: Requesting user bridge token from https://prod.truv.com/v1/users/{user_id}/tokens")
	log.Printf("TRUV: User ID - %s\n", userId)
	productType := os.Getenv("API_PRODUCT_TYPE")
	bridgeTokenRequest := BridgeTokenRequest{
		ProductType:  productType,
		TrackingInfo: "1338-0111-A",
	}
	if productType == "pll" || productType == "deposit_switch" {
		account := AccountRequest{
			AccountNumber: "1600200",
			AccountType:   "checking",
			RoutingNumber: "123456789",
			BankName:      "TD Bank",
		}
		if productType == "pll" {
			account.DepositType = "amount"
			account.DepositValue = "1"
		}
		bridgeTokenRequest.Account = &account
	}
	bridgeJson, _ := json.Marshal(bridgeTokenRequest)
	request, err := getRequest(fmt.Sprintf("users/%s/tokens/", userId), "POST", bridgeJson)
	if err != nil {
		return "", err
	}
	client := &http.Client{}
	response, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer response.Body.Close()
	data, _ := ioutil.ReadAll(response.Body)
	return (string(data)), nil
}

Initializing Truv Bridge

Users log into their payroll accounts through Truv Bridge. After retrieving the bridge_token, use that value to initialize the Bridge. Truv Bridge is a client-side module to handle the authentication process. It’s available as a drop-in for web clients, iOS, and Android platforms.

For the Quickstart app, the Bridge module is on the web. It uses a JavaScript integration triggered from client-side code. In the front-end, the application runs TruvBridge.init to pass the bridge_token from the back-end. From there, it assigns callback functions as needed. View the code sample below for more details.

const bridge = TruvBridge.init({
  bridgeToken: bridgeToken.bridge_token,
  onLoad: function() { ... },
  onSuccess: function(public_token, meta) { ... },
  onEvent: function(event_type, payload) { ... },
  onClose: function() { ... }
});
window.bridge = bridge;

Submitting credentials for public_token

Truv Bridge provides you with a public_token value after a user submits their credentials. This happens through the onSuccess callback. The JavaScript code below covers the public_token exchange between the client-side code and the server.

onSuccess: async function (token) {
  console.log('token: ', token);
  successClosing = true
  const content = document.querySelector('.spinnerContainer');
  content.classList.remove('hidden');
  let verificationInfo;
  try {
    verificationInfo = await apiRequests.getVerificationInfoByToken(token);
  } catch(e) {
    console.error(e)
    content.classList.add('hidden');
    return;
  }
  content.classList.add('hidden');
  if (!verificationInfo.length) {
    return;
  }
},
...
onClose: function () {
  console.log('closed');
  if (successClosing !== true) {
    renderEmploymentHistory([{ company: { address: {} } }]);
  }
},

📘

Note

The public_token is temporary and expires after 6 hours.

Server side exchanges

The quickstart application goes through the server to Retrieve a link token for the access_token and a link_id. These two new values are required to identify a Link. Truv API endpoints also require these values as arguments. Like with other important values, store the access_token and link_id in a secure and private location when making API requests.

The code samples below demonstrate the server actions.

def get_access_token(self, public_token: str) -> dict:
    logging.info(
      	"TRUV: Exchanging a public_token for an access_token from https://prod.truv.com/v1/link-access-tokens"
    )
    logging.info("TRUV: Public Token - %s", public_token)

    return self.post(
        "link-access-tokens/",
        json={
          	"public_token": public_token,
        },
    )
const getAccessToken = async (public_token) => {
  console.log('TRUV: Exchanging a public_token for an access_token from https://prod.truv.com/v1/link-access-tokens');
  console.log(`TRUV: Public Token - ${public_token}`);
  const body = JSON.stringify({
    public_token: public_token,
  });
  const responseBody = await sendRequest('link-access-tokens/', { body });
  return responseBody;
};
func getAccessToken(public_token string) (string, error) {
	log.Println("TRUV: Exchanging a public_token for an access_token from https://prod.truv.com/v1/link-access-tokens")
	log.Printf("TRUV: Public Token - %s\n", public_token)
	publicToken := PublicTokenRequest{PublicToken: public_token}
	jsonPublicToken, _ := json.Marshal(publicToken)
	accessToken := AccessTokenResponse{}
	request, err := getRequest("link-access-tokens/", "POST", jsonPublicToken)
	if err != nil {
		return "", err
	}
	client := &http.Client{}
	res, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer res.Body.Close()
	err = json.NewDecoder(res.Body).Decode(&accessToken)
	if err != nil {
		return "", err
	}
	return accessToken.AccessToken, nil
}

Example income and employment report

The examples below go over requesting an income and employment report after a successful connection. These use the quickstart app to Retrieve an income and employment report for more about the user’s profile, company, and other employment information.

def get_income_info_by_link_id(self, link_id: str) -> dict:
    logging.info(
      	"TRUV: Requesting income report data from https://prod.truv.com/v1/links/:link_id/income/report"
    )
    logging.info("TRUV: Link ID - %s", link_id)

    return self.get(f"links/{link_id}/income/report")
const getIncomeInfoByLinkId = async (link_id) => {
  console.log(
    'TRUV: Requesting income verification data from https://prod.truv.com/v1/links/:link_id/income/report',
  );
  console.log(`TRUV: Link ID - ${link_id}`);
  return await sendRequest('links/${link_id}/income/report', { method: "GET" });
};
func getIncomeInfoByLinkId(link_id string) (string, error) {
  log.Println("TRUV: Requesting income verification data from https://prod.truv.com/v1/links/:link_id/income/report")
	log.Printf("TRUV: Link ID - %s\n", link_id)
  request, err := getRequest(fmt.Sprintf("links/%s/income/report", link_id), "GET", nil)
	if err != nil {
		return "", err
	}
  
	client := &http.Client{}
	res, err := client.Do(request)
	if err != nil {
		return "", err
	}

	defer res.Body.Close()
	data, _ := ioutil.ReadAll(res.Body)
	return string(data), nil
}

Example response data

This JSON object is a sample payload for the income and employment report request.

{
  "id": "24d7e80942ce4ad58a93f70ce4115f5c",
  "status": "new",
  "completed_at": "2021-04-06 11:30:00+00:00",
  "access_token": "48427a36d43c4d5aa6324bc06c692456",
  "tracking_info": "user123456",
  "refresh_status": "new",
  "employments": [
    {
      "id": "24d7e80942ce4ad58a93f70ce4115f5c",
      "job_title": "PR associate",
      "job_type": "F",
      "start_date": "2018-01-01",
      "end_date": "2019-08-24",
      "external_last_updated": "2019-08-24",
      "original_hire_date": "2017-06-21",
      "is_active": false,
      "dates_from_statements": false,
      "derived_fields": [
        "is_active"
      ],
      "missing_data_fields": [
        "w2s"
      ],
      "profile": {
        "first_name": "John",
        "last_name": "Doe",
        "middle_initials": "K",
        "ssn": "123456789",
        "email": "[email protected]",
        "date_of_birth": "1992-03-03",
        "home_address": {
          "street": "1 Morgan Ave",
          "city": "Los Angeles",
          "state": "CA",
          "zip": "90210"
        }
      },
      "company": {
        "name": "Facebook Demo",
        "address": {
          "street": "1 Hacker Way",
          "city": "Menlo Park",
          "state": "CA",
          "zip": "94025"
        },
        "phone": "6503087300"
      },
      "income": "70000.00",
      "income_unit": "YEARLY",
      "pay_frequency": "M",
      "manager_name": "Jenny McDouglas",
      "statements": [
        {
          "id": "24d7e80942ce4ad58a93f70ce4115f5c",
          "pay_date": "2018-05-15",
          "net_pay": "11500.32",
          "net_pay_ytd": "31980.64",
          "gross_pay": "13900.11",
          "gross_pay_ytd": "49200.00",
          "bonus": "100.00",
          "commission": "12000.00",
          "hours": "40.00",
          "basis_of_pay": "S",
          "period_start": "2018-05-01",
          "period_end": "2018-05-15",
          "regular": "1695.11",
          "regular_ytd": "23000.00",
          "bonus_ytd": "1000.00",
          "commission_ytd": "24000.00",
          "overtime": "45.00",
          "overtime_ytd": "500.00",
          "other_pay": "60.00",
          "other_pay_ytd": "700.00",
          "earnings": [
            {}
          ],
          "earnings_ytd": [
            {}
          ],
          "deductions": [
            {}
          ],
          "deductions_ytd": [
            {}
          ],
          "md5sum": "03639d6a6624f69a54a88ea90bd25e9d",
          "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/paystub_sample.pdf"
        }
      ],
      "annual_income_summary": [
        {
          "id": "24d7e80942ce4ad58a93f70ce4115f5c",
          "year": 2018,
          "regular": "23000.00",
          "bonus": "1000.00",
          "commission": "24000.00",
          "overtime": "500.00",
          "other_pay": "700.00",
          "net_pay": "31980.64",
          "gross_pay": "49200.00"
        }
      ],
      "bank_accounts": [
        {
          "account_number": "1234567890",
          "routing_number": "123456789",
          "account_name": "My Bank",
          "account_type": "C",
          "deposit_type": "A",
          "deposit_value": "200.00",
          "bank_name": "TD Bank"
        }
      ],
      "annual_salary": "70000.00",
      "hourly_salary": "36.40",
      "w2s": [
        {
          "file": "https://citadelid-resources.s3-us-west-2.amazonaws.com/W2_sample.pdf",
          "md5sum": "f65e30c39124ad707ac4b3aeaee923a7",
          "year": 2020
        }
      ]
    }
  ],
  "provider": "adp"
}

Next steps

👍

Congratulations!

You've completed the Truv Quickstart!

Use the quickstart code samples as an opportunity to expand on your experience with the Truv API.

Product guides

Learn more about our products through the guides below.

Mobile integrations

For mobile integrations of Truv, learn more about getting started through the Bridge SDK .

Demo applications

Our sample apps page has additional examples, including real-world use cases.


What’s Next

Learn more about other products, such as verifying income and employment and other guides and check out our Postman Collection as well.