Platform Selector


Overview

In this article, we talk about techniques for how to keep your Foundry learners in sync with your system of record by using the Foundry API. We’re written this article for an audience of general technologists as well as software developers, so there are a few code samples, but we believe that anyone with a basic knowledge of APIs and integration technologies can follow along. This article is a complement to our Foundry API documentation. The API documentation explains each operation in greater detail, and this article weaves that information into a higher-level guide for your overall integration flow.

What we are trying to solve is the following: Foundry is EVERFI’s digital learning platform. Unless you have a LMS integration in which you administer all the learners entirely in the LMS, then in Foundry you will need all your learners to be added as users. This way, in Foundry you can track your learners’ progress, assign specific learning content to them, send them invitation and reminder emails, etc. Knowing that your learners need to be users in Foundry, the next thing to consider is: how do you get them into Foundry, with the right information needed to make appropriate assignments? And how do you keep your learners’ profiles up to date as the information about them changes in your system of record? With an integration to the Foundry API, you can perform these tasks automatically.

For the purpose of this case study, we will assume a one-way sync from your system of record to Foundry. In other words, if someone has a name change, then the name change will be recorded in the system of record, and that name change eventually will flow into Foundry. Not the other way around; changes to a person’s core information will not originate in Foundry.

Depending on your scenario, we have a couple of possible ways to keep your learners information accurate and up to date in Foundry through the API.


Glossary

Let’s start with a few terms:

Foundry – EVERFI’s digital learning platform.

HRIS – Human Resources Information System. Alternately, you might have your learners in a CRM or a student registration system, or even a mix of systems. For simplicity, in this case study we will call this system the HRIS.

Learner – a person who participates in a Foundry learning activity. Every learner must be a user in Foundry and also have a record in the HRIS.

API – the application programming interface component of Foundry, which lets systems like your HRIS exchange data with Foundry.

Foundry User – every learner must be a Foundry user; a learner and a user are almost interchangeable. A user has a first name, last name, email, location, single sign-on ID (if you have a single sign-on integration), an optional student ID or employee ID, plus any optional demographic attributes called Category-Labels, which are typically used to assign specific courses to specific populations. You might use Category-Labels to classify people into departments, geographic locations, matriculation year, or other characteristics. A user also has a type and a role, and may be active or inactive. A user also has a unique identifier that is used as a primary key in the API; this field is the Foundry User ID.

Integration platform – your HRIS likely has a tool or extension that enables you to connect different external systems to your HRIS. Your HRIS may have its own native integration tool, or you may have a separate integration platform that is compatible with your HRIS, or you may have a home-grown application that facilitates information exchanges between your HRIS and external applications. It is your integration platform that will interact with the Foundry API. Your platform may have built-in tools that can interface with an API, or you may need your IT staff to write programming code to “talk” to the API, or some blend of the two.


Scenarios

Depending on the capabilities and flexibility of your HRIS, there may be several ways to sync your users.

Ideally, you’ll have a way in your HRIS system to keep a running delta of changes to individuals, so that each time you need to sync users, you’ll be able to sync only the changes (including adds and deletions) and not have to sync every single user every single time, including users who haven’t changed at all. If you isolate only those learners who actually need to be updated in Foundry, then you’ll reduce the amount of processing you need to do and make the sync process run faster.

That being said, we recognize that some systems are complicated and are comprised of a lot of different inputs and moving parts, and that it might not be so easy to identify all the learners who have changed since you last ran the sync 24 hours ago. So for these situations, it may be more straightforward and safer to simply sync every user, every time, even if they haven’t changed. We get that.

It’s also ideal if you can store the Foundry User ID about each learner in your HRIS or integration platform, if possible. This will make syncs easier because you know how to match the users between both systems. But we recognize that you don’t always have that ability.

Next, we’ll discuss the API techniques you can use to sync your users, and how these techniques are affected based on how you can handle the considerations above.


API Capabilties

Before we discuss the various integration flows, let’s cover what you can actually do with the Foundry API. The API is a restful web service that enables you to retrieve, create and update users, among other things. You can retrieve multiple users in one API request, but to add or update a user, you can manage one user per request. To update an existing user, you must provide that user’s Foundry ID.

To use a common term, the API supports CRUD methods – create, read, update and delete (although the “delete” is really “deactivate”—for compliance reasons, you cannot delete a Foundry user).

Your application must authenticate first to run any API operations through OAuth 2.0, a common authentication protocol.


API Sync Techniques

Before we get into the specifics, we want to say that there is not a single right way to use the API and to arrange your integration flow. We realize that everyone has different systems, different constraints, and different ways to sync data. The techniques we outline below are just one way, and you may of course adapt these techniques to fit into your own personalized environment. Fortunately, the Foundry API is flexible enough that it doesn’t “care” how you arrange your overall integration flow, as long as you run the standard API operations to retrieve, add and update users. The flows we recommend below are based on our experience in working with many Foundry clients and represent a general best practice that we’ve seen work for most organizations.


Simple User Sync Scenario

Let’s start with the easiest scenario: your HRIS is able to isolate the user additions, deletions and changes between each sync, and you are recording the Foundry User ID in your system of record.

In this scenario, for each new learner, you will add the user in Foundry via the API. In the response to a successful add, you get back the Foundry User ID so you record that with the user record in your HRIS. For each change to an existing learner, you will PATCH the user by ID. And for each deletion, you will PATCH the Foundry User by their ID, and mark their user record as inactive; this is essentially a variation of the previous example.

Here’s a sample cURL code fragment showing how to add a new user with a POST. Refer to our API technical documentation more specifics on each property.

curl --location --request POST 'https://api.fifoundry.net/v1/admin/registration_sets' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer fyJ0eXA....yNI7FaYnkPGDxQ' \
--data-raw '{
    "data": {
        "type": "registration_sets",
        "attributes": {
            "registrations": [
                {
                    "rule_set": "user_rule_set",
                    "first_name": "First",
                    "last_name": "Last",
                    "email": "myemail@stateu.edu",
                    "sso_id": "000045305",
                    "student_id": "000045305",
                    "location_id": 10415,
                    "category_labels": [
                        "2762",
                        "2759"
                    ]
                },
                {
                    "rule_set": "he_learner",
                    "role": "undergrad"
                }
            ]
        }
    }
}'

Here’s a sample cURL code fragment showing how to update an existing user in a PATCH request. This is a variation of the request above, with the only difference being that you supply the user’s Foundry ID. You must send all the user’s data in a PATCH request, even for the data fields that haven’t changed.

curl --location --request PATCH 'https://api.fifoundry.net/v1/admin/registration_sets/4e288764-c47e-4d06-9bcd-defa9a5ade47' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: Bearer fyJ0e....9KRxByNI7FaYnkPGDxQ' \
--data-raw '{
    "data": {
        "type": "registration_sets",
        "id": "4e288764-c47e-4d06-9bcd-defa9a5ade47",
        "attributes": {
            "registrations": [
                {
                    "rule_set": "user_rule_set",
                    "first_name": "My",
                    "last_name": "Lastname",
                    "email": "user_11@stateu.edu",
                    "location_id": 1712,
                    "employee_id": "000045305",
                    "sso_id": "000045305",
                    "active": true,
                    "category_labels": [
                        "2969",
                        "2967"
                    ]
                },
                {
                    "id": "4e288764-c47e-4d06-9bcd-defa9a5ade47",
                    "rule_set": "fac_staff_learner",
                    "role": "non_supervisor",
                }
            ]
        }
    }
}'

To deactivate a user, simply send a PATCH request just like the one above and set active to false.

In the easy scenario, you don’t need to retrieve users from Foundry at all, because your HRIS already knows who they are (it records the Foundry User ID in the HRIS) and you know who is in Foundry and who isn’t.


Complex Sync Scenario

Now let’s consider a more complex scenario, in which it’s not practical or possible to “know” whether a user needs to be synced or not, and you don’t have the users’ Foundry IDs in your HRIS. This means that each integration run, you need to perform a full sync which includes a sequence to match HRIS users with their Foundry counterparts.

To start this routine, your integration code will first get from your HRIS the set of all learners that need to be in Foundry. Plus any users who need to be removed if they are no longer a part of your organization. At this point, you don’t know if they are in Foundry or not, you just know they need to be in Foundry. Or that they need to be deactivated if they’ve departed your organization.

As in the simple scenario we covered earlier, start with a list of all the individuals in your HRIS who need to be added or removed from Foundry.

Then GET all the Users from Foundry via the API via a series of paged GET requests to the User route. This route returns at most 100 results per request, so you’ll need to page through a series of requests to get all users. Here is a GET request for page 1:


curl --location --request GET
   'https://api.fifoundry.net/v1/admin/users/
   ?page[number]=1
   &page[size]=100
   &fields[users]=email,first_name,last_name,sso_id,employee_id,
      student_id,location_id,active,user_rule_set_roles,category_labels' \

--header 'Content-Type: application/json' \

--header 'Accept: application/json' \

--header 'Authorization: Bearer eyJhbGciO...oNRNTNQ'

The response includes a links.next URL that tells you what the next page is. Keep sending requests until you get to the end.

Here’s an extract of one user in the response. This schema is similar to the payload you send for a POST or PATCH request to create or update a user.

{
    "id": "fb65d257-5671-4966-8526-28fcf81e689c",
    "type": "users",
    "attributes": {
        "active": true,
        "email": "hello@adfasd.com",
        "employee_id": null,
        "first_name": "Geoff",
        "last_name": "Smith",
        "location_id": 4146,
        "sso_id": "hello@adfasd.com",
        "student_id": "0023872873",
        "user_rule_set_roles": [
            {
                "rule_set": "he_learner",
                "role": "undergrad"
            }
        ]
    },
    "relationships": {
        "category_labels": {
            "data": [
                {
                    "id": "575",
                    "type": "category_labels"
                }
            ]
        }
    }
}

Now that you have all the users out of Foundry, “assemble” them into a searchable list in whatever format or container your integration platform supports.

At this point, your program will now have two big lists: the list of HRIS users you got from your system of record, and the list of Foundry users you got from the API. The next step is to reconcile those lists.

Loop through each HRIS user and try to find that user in the Foundry user list you assembled from the series of GET requests. Depending on your configuration, the matching key between users might be student ID, employee ID, SSO ID or email address. Be aware that email address as a matching key can be problematic because people’s email addresses can change. Therefore, to match users across both systems, it’s ideal to use an immutable value like student ID or employee ID, or SSO ID if that is an immutable value (and not a value that can change like email address or a username).

If you find a match, then perform a comparison on all the learner’s information. If any value differs between the HRIS representation of the user and the Foundry user, then update the user via the Foundry API. If all the information is the same, then no update is needed, so skip to the next user. For departing learners, you’ll also perform an update and set their active flag to false.

If you cannot find the user in Foundry, then add the User to Foundry via the API.

To be complete, you might also want to handle any user who is in the Foundry list but not your HRIS list. Presumably this Foundry user should be deactivated because they are no longer recognizable in your HRIS as a valid individual.

You’ve now synched your users in Foundry.


Example

Here is a simplified example of all this in action.

Between these two lists you can find an example of several cases. For this organization, the SSO ID value is used as the matching key between the individuals in the HRIS and the users in Foundry. As described elsewhere in this article, your organization may use a different field for matching.

HRIS User List
SSO ID First Last Active
33 Geoff Smith-Evans T
44 Kate Jones T
55 Leo Later F
686 Ellen Cohen T
77 Mike Morris F

Foundry User List

Foundry ID SSO ID First Last Active
dek-123 33 Geoff Smith T
zak-928 44 Kate Jones T
iux-332 55 Leo Later T
qai-928 787 Dan Dismayed T

 

Here’s how you can handle each user, examining each user in the HRIS User List from top to bottom, and then looking at the users in Foundry User List:

  • For the HRIS user 33 (Geoff Smith-Evans) the user can be found in Foundry as the user with SSO ID 33. A delta comparison of each user property finds that the user’s last name has changed from “Smith” to “Smith-Evans”. Therefore, the integration must send a PATCH request to update this existing user’s last name, sending dek-123 as the Foundry User ID.
  • Moving down the list, user 44 can be located in Foundry, but a delta comparison of each user property finds that the values in each system are identical, so no action on this user is needed.
  • User 55 is inactive in the HRIS but active in Foundry, so similar to user 33, send a user PATCH request and set active to false to deactivate the user in Foundry. For a re-hire, where the user still has the same identifier and goes from inactive to active, you would send a user PATCH request and set active to true.
  • User 686 cannot be located in Foundry, so send a user POST request to add the new user to Foundry.
  • User 77 is inactive in your HRIS and does not exist in Foundry at all, so no action is needed.
  • Finally, if you look at the Foundry users, each has been accounted for in the HRIS with the exception of user 787, Dan Dismayed, who exists in Foundry as an active user but is not in your HRIS. While this exception theoretically shouldn’t happen, you may want to handle this sort of case with an exception file for a staff member to manually figure out, or consider deactivating the user in Foundry.

What Happens When You First Turn on the API?

Suppose that when you first turn on the API integration, that in Foundry, you have only a few users that you or EVERFI previously added manually. If you set up your integration right, then the integration would simply find that just about every person in your HRIS system doesn’t exist in Foundry, so in that inaugural integration run, you would get lots of new users added.

When the integration runs a second time, lets say 24 hours later, that synch would only add in the handful of users who might have been added in the preceding 24 hours, plus a smattering of updates that also happened within that 24 hours.

When you look at it this way, you don’t really need special handling for the first API run and a subsequent one; the first API run simply has many more inserts to make, and not many updates. If you’re concerned that the first API run will have too much going on, then you can always bulk add the initial set of users via a text file import in the customer admin portal, and then turn on the API integration after the initial upload.


Additional Considerations

In this section, we cover some additional topics in more detail, in no particular order.

How often should you sync your users? Most EVERFI clients run a daily sync but depending on your needs you can sync more or less frequently.

If your sync is sending many request in a short burst of time—which it probably will—be sure to add some throttling to ensure you stay under the API rate limit of 200 requests per rolling 60 seconds. If you receive a 429 “too many requests” response to your request, then slow down your thread and retry after a pause.

Learner reactivations – if a learner is reactivated (e.g. an employee who left but then was rehired), then be sure to include deactivated Foundry users in your GET requests so you can reactivate the user in your API integration.

Separating core learner updates from demographic updates – you may wish to split the updates of core personal information like name and email from demographic updates to specific category-label updates. You may even wish to have certain parts of your data synch update only a specific category. This may be appropriate if separate systems control different categories. The Foundry API has routes to allow you to set a user’s categories independently of updating the user’s core personal information. You may find it more convenient to split your sync into one routine that updates core personal information, and separate routines that exclusively update categories. You have that choice.

Be aware that Foundry users include both ordinary learners and also has “power users” called customer admins who may or may not also be ordinary learners. A customer admin is able to log into an admin console in Foundry to manage users, make assignments, and do other activities. If you’re reading this article, there’s a good chance you’ll be one of these users. Be sure to account for these users in your user sync because they can be returned with the user GET response. Admin users will have a different user type (rule_set) than ordinary learner users.

Once you have set up your categories and labels, you probably will not change them regularly. But if you need to add new Labels or Categories in the API as part of your user sync, that’s possible as well.

Assigning learning activities via the API? You might ask, when users get added in the API, how are they assigned content? Can you assign learning activities via the API? In Foundry, you don’t make assignments via the API, but you can create automated assignments in Foundry that auto-assign learning activities to users who meet the criteria you set. So if you add a new user, or update an existing user, and the user meets the criteria for the assignment, then they’ll get assigned those learning activities.

Retrieving users one at a time instead of in bulk – if your integration scenario calls for retrieving one Foundry user at a time instead of in bulk, that can work, although it will obviously require your integration to make a great deal more API requests. The API allows you to search for a user via several fields: Foundry User ID, employee ID, student ID, email address or SSO ID.


Summary

We hope this deep dive overview helps you think about how you can sync your organization’s users into Foundry via the API. Please contact us if you have any questions or if you’d like to talk through your own unique scenario.