Automate your payroll with Gusto | Kinderlime
  • by Andy
  • on

Automate your payroll with Gusto

At Kinderlime we solve hard challenges facing childcare market today through our all-in-one platform. One of the big challenges the industry faces is easy and quick way to run payroll based on staff/employees working hours.

 

Kinderlime with our mobile kiosk based solution seamlessly captures daily clock in-out times of all the staff. Even though we calculate working time for each staff member per any period of time, it still is difficult to process and manually update those hours to a payroll system. This is where Gusto steps in.

 

Gusto is an easy online payroll service for small business. It is known for its simplicity and saving time spent on payrolls. Kinderlime deeply integrates with Gusto and running payroll for clocked-in staff becomes so much easy.

In this article, I mention about product and technical details on how we integrate.

 

One time Authorization

You will connect Gusto to Kinderlime after you login to Kinderlime:

  • Go to “School Settings” -> “Integrations” page
  • Click “Connect” button and provide Gusto credentials to authorize Kinderlime

Gusto uses OAuth2, so once you click “Connect” we take user to https://api.gusto.com/oauth/authorize.  

Gusto redirects user back to our Kinderlime website with “code” param in URL once you authenticate.

We fetch this “code” and use it in next request to get the “access_token”. We send POST to https://api.gusto.com/oauth/token with these params:

  • client_idKinderlime app client id
  • client_secretKinderlime app client secret
  • redirect_uriSame URL we used for the first authorize request
  • codeThe code we fetched from params
  • grant_typeliteral string “authorization_code”

Sample response body:

{
    "access_token": "de6780bc506a0446309bd9362820ba8aed28aa506c71eedbe1c5c4f9dd350e54", 
    "token_type": "bearer", 
    "expires_in": 7200, 
    "refresh_token": "8257e65c97202ed1726cf9571600918f3bffb2544b26e00a61df9897668c33a1"
}

From now on we use “access_token” from last response as bearer token for all our future requests. This means we include this header everywhere:

Authorization: Bearer access_token

 

 

Syncing Employees

Once connected with Gusto, Kinderlime automatically fetches all employees from Gusto and checks if they exist as staff in Kinderlime. We match them either by email or name. If no match is found, then new staff gets created in Kinderlime.  If you are keen then you might want to calculate Edit Distance to account for mistyped ones.

Whenever staff member gets deactivated from Kinderlime, we automatically unlink with corresponding employee in Gusto so payroll hours don’t get updated from Kinderlime.

To create, update or unlink staff we fetch all employees from Gusto. GET request https://api.gusto.com/v1/companies/:company_id/employees with these params:

  • terminated – literal string “false” in order to fetch only active employees

Sample response body:


[
  {
    "id": 1123581321345589,
    "version": "db0edd04aaac4506f7edab03ac855d56",
    "first_name": "Soren",
    "middle_initial": "A",
    "last_name": "Kierkegaard",
    "company_id": 7757616923531095,
    "manager_id": 7757869431804236,
    "department": "Finance",
    "email": "knight0faith@learning.net",
    "ssn": "XXX-XX-2940",
    "date_of_birth": "1990-05-05",
    "jobs": [
      {
        "id": 1,
        "title": "Finance Controller",
        "rate": "60000.00",
        "payment_unit": "Year",
        "location_id": 3141592653589793
      }
    ],
    "home_address": {
      "id": 1402342024000,
      "version": "fe75bd065ff48b91c35fe8ff842f986c",
      "employee_id": 1123581321345589,
      "street_1": "425 2nd Street",
      "street_2": "Suite 602",
      "city": "San Francisco",
      "state": "CA",
      "zip": "94107",
      "country": "USA"
    },
    "garnishments": [ ],
    "eligible_paid_time_off": [],
    "onboarded": true,
    "terminated": false,
    "terminations": []
  }
]

 

 

Calculation of Worked Hours for Payroll

Payroll hours for each staff are updated in real-time. On every clock in-out record changes, Kinderlime automatically syncs latest calculated total work hours for the unprocessed payroll period in Gusto.

The working hours are always calculated with maximum precision. We sum all the worked hours in seconds for all clock in-out records across unprocessed payroll period, then convert them to hours before updating through Gusto API.

Unprocessed payrolls can be fetched by GET request to https://api.gusto.com/v1/companies/:company_id/payrolls with params:

  • processed – literal string “false” in order to fetch only non-processed payrolls
[
  {
    "version": "19289df18e6e20f797de4a585ea5a91535c7ddf7",
    "payroll_deadline": "2018-02-18",
    "processed": false,
    "pay_period": {
      "start_date": "2018-02-01",
      "end_date": "2018-02-15",
      "pay_schedule_id": 7757500908984137
    },
   
    "employee_compensations": [
      {
        "employee_id": 1123581321345589,
        "gross_pay": "2791.25",
        "net_pay": "1953.31",
        "payment_method": "Direct Deposit",
        "fixed_compensations": [],
        "hourly_compensations": [
          {
            "name": "Regular Hours",
            "hours": "32.00",
            "job_id": 1,
            "compensation_multiplier": 1
          }         
        ],
        "paid_time_off": [],
        "benefits": [],
        "taxes": [
          {
            "name": "Federal Income Tax",
            "employer": false,
            "amount": "646.69"
          },
          {
            "name": "Social Security",
            "employer": true,
            "amount": "191.25"
          }
        ]
      }
    ]
  }
]

 

We loop through “employee_compensations” array and look for a linked staff member on Kinderlime side.

For each linked staff, we fetch Clock In-Out records for corresponding payroll time period (from “start_date” to “end_date”) with respect to a school’s timezone and calculate total worked hours.

 

Let’s say the calculation came to 40 hours as total worked time, then you will build your response like here and update it through PUT request to https://api.gusto.com/v1/companies/:company_id/payrolls/ :pay_period_start_date/:pay_period_end_date:

{
  "version": "19289df18e6e20f797de4a585ea5a91535c7ddf7",
  "employee_compensations": [
    {
      "employee_id": 1123581321345589,
      "hourly_compensations": [
        {
          "name": "Regular Hours",
          "hours": "40.00",
          "job_id": 1,
          "compensation_multiplier": 1
        }
      ]
    }
  ]
}

Refer: https://docs.gusto.com/ for more details around integration with gusto api.