Single API for Users with Relationships and Related User Details?

Hi everyone,

We’re trying to optimize our integration and reduce the number of API calls during synchronization.

Our requirement is to retrieve all users in a single API call, including:

  • Basic user details
  • All associated relationships (e.g., Parents, Staff)
  • Related user details for those relationships
  • Additional fields like student_id and any custom fields

The goal is to avoid making multiple API calls (per user or per relationship), which is currently impacting performance — especially when working with multiple schools (tenants).

Has anyone implemented something similar?

  • Is there any API that returns users along with their relationships and related user details in one response?
  • Or is there any supported approach (e.g., parameters, expansions, batching strategies) to achieve this efficiently?

Would appreciate any guidance or best practices from others who’ve worked on this.

Answers

  • Alex Wong
    Alex Wong Community All-Star
    Tenth Anniversary Kudos 5 Facilitator 4 bbcon 2025 Attendee Badge

    Assuming you are talking Education Management, then I do not have anything that can help you as I do not use that platform.

    If you are talking about RE NXT, then most data can be obtained in bulk either via various "list api" (constituent list) or query api.

  • Hi Alex Wong,

    Yes, I’m referring to Education Management. I’m currently implementing a user sync from Blackbaud to our application using SKY APIs.

    Our requirement is to retrieve all users in a single API call, including:

    • Basic user details
    • All associated relationships (e.g., Parents, Staff)
    • Related user details for those relationships
    • Additional fields such as student_id and any custom fields

    If you have any experience with SKY APIs for Education Management—or could point me to someone who does—it would be very helpful.

    Appreciate your guidance.

  • Brian Gray
    Brian Gray Community All-Star
    Ninth Anniversary Kudos 5 First Reply bbcon 2025 Attendee Badge

    You will probably not get everything you are looking for in a single call to the API.

    My approach for what you describe is to call the User Extended Get endpoint with multiple base_role_id values (a string that is a comma-separated list of base_role_id values). The Relationships array that is returned as part of the data for each user will include family relationships as defined on the Contacts tab of the user's record in Core. This may include parents, guardians, siblings, grandparents, etc.

    My program reads all of the user records and stores them in a hashtable (key = user's ID field). The relationships include the user IDs for both people, so when I am processing a student's record I can cycle through the relationships and do a lookup based on the user ID of the people in the relationships of interest.

    The Relationship array does NOT include a student's teachers, advisors, coaches, etc. Those relationships are recorded in the roster of groups that the student is part of.

  • Thank you for the clarification.

    We understand that retrieving all data in a single API call may not be possible. However, we have concerns regarding the use of the Extended Users endpoint with base_role_id filtering.

    In our concern, a base_role_id can have multiple roles assigned simultaneously. For example:

    [  { "id": 4184, "base_role_id": 14, "hidden": false, "name": "Student" },  { "id": 4204, "base_role_id": 14, "hidden": false, "name": "System Group Manager" },  { "id": 4205, "base_role_id": 14, "hidden": false, "name": "Content Manager" }]
    

    In this scenario, even though the base_role_id corresponds to “Student,” additional roles are still associated with the same user.

    Since the school requirement is to retrieve only users with the Student role, could you please clarify:

    • Is there a way to ensure we fetch only “pure” Student users (i.e., users without any additional roles)?
    • Or should we consider a user as a Student if they have the Student role, regardless of other assigned roles?

    We want to ensure our filtering logic aligns with best practices and avoids incorrect data synchronization

    image.png
  • Brian Gray
    Brian Gray Community All-Star
    Ninth Anniversary Kudos 5 First Reply bbcon 2025 Attendee Badge

    Few uses have just one role. The All School role (base_role_id 1) is applied to all records. Current users will usually have at at least one other role (Student, Parent, Teacher, etc). It's common for employees to have many roles.

    For me, if a record has the Student role, then the user is a student - regardless of what other roles are also assigned to the user. That may or may not make sense for your project.

  • Thank you, Brain Gray, I believe I may have miscommunicated my earlier point.

    In the example I shared, the roles response is:

    [  { "id": 4184, "base_role_id": 14, "hidden": false, "name": "Student" },  { "id": 4204, "base_role_id": 14, "hidden": false, "name": "System Group Manager" },  { "id": 4205, "base_role_id": 14, "hidden": false, "name": "Content Manager" }]
    

    From the Core Roles endpoint (/school/v1/roles), we observe that multiple roles share the same base_role_id.

    Could you please confirm whether a single base_role_id is expected to map to multiple roles, or if it should represent a single primary role?


  • Could someone please confirm whether a single base_role_id is expected to map to multiple roles, or if it is intended to represent a single primary role?

    @Stephen Boyle, could you please clarify this as well?

  • Eric Eskildsen
    edited April 6

    Hi @Dakshesh Dave - a single base role ID can map to multiple roles, yes.

    Base role IDs are the same across schools. Example: 14 is the base role ID for Student, for all schools.

    Role IDs, on the other hand, are unique to the school. One school's Student role ID could be 123. Another's could be 456.

    My mental model is that a base role is like a base class in object-oriented programming. Or you could say it's like a template in Microsoft Word, and a role is like a "document" that was created from that "template."

  • Eric Eskildsen
    edited April 6

    @Dakshesh Dave

    To add to this: A school can create their own roles based on a base role. Here's an example….

    Out of the box, not all employees are included in Blackbaud's OneRoster exports. Only teachers are. Blackbaud determines who's a teacher by looking for users with the Teacher base role.

    Some schools want to include non-teaching staff as well. So, they've created their own custom role based on the Teacher base role. They assign that role to their non-teaching staff. Then Blackbaud includes them in the exports.

    That's one example, anyway. … Hope something here helps!

  • Thank you, @Eric Eskildsen, for the explanation, it really helped clarify things.

    In our case, each school decides which roles should be included in the sync, such as Student, Staff, Parent, Grandparent, Manager, Coach, and Dorm Supervisor.

    That said, since a single base_role_id can correspond to multiple roles, we’re finding it challenging to accurately filter the exact users we need when relying only on base roles.

    Would you recommend using role_id, possibly in combination with the Extended Users List API response, to achieve more precise filtering? If there are any best practices for handling this consistently across different schools, we would greatly appreciate your guidance.

  • Eric Eskildsen
    edited April 6

    No problem!

    If you let schools pick their own roles, I'd say yes, do what you suggested. Use role_id in combination with /users/extended. Get all users from /users/extended and then filter on your side.

    So, in your /users/extended call, set base_role_ids to 1. That will fetch all users in the school. Then filter on roles.

    Say one of the users in the /users/extended response has these roles:

    "roles": [
    {
    "id": 5559992,
    "base_role_id": 1,
    "hidden": false,
    "name": "All School"
    },
    {
    "id": 8880001,
    "base_role_id": 14,
    "hidden": false,
    "name": "Student"
    }
    ]

    Those ID values match the school-specific role IDs from /roles.

    Let's say that school had asked you to sync only the Student role. Their Student role ID is 8880001. So, you could filter your /users/extended response to only include users where any of their roles had ID 8880001.

    It's too bad /users/extended doesn't have a role_ids parameter as an alternative to base_role_ids. role_ids would let you get the exact data you need; the filtering would happen on Blackbaud's side. /users does have role_ids as you've probably seen, but it doesn't have all the data you need. So, I'd say /users/extended with filtering on your side is probably your best option.

  • Hi @Eric Eskildsen ,

    Thanks for the suggestion, that approach makes sense.

    We just have one clarification:
    Do all roles always have a base_role_id, or is it possible for this field to be null or empty in some cases?

    If you could confirm, it would help us ensure our filtering logic is robust.

    Appreciate your guidance.

Categories