Connecting to Raiser's Edge API with Axios

Hi, I am looking to connect to RE NXT's API using Axios and I am curious about setting up a request to do this. I have the “Bb-Api-Subscription-Key" and I am wondering if anyone else has experience with this for data integration and can help me structure the Axios request.

Our organization is trying to make a REST call to make what we call a shadow copy of constituents, notes and gifts.

Comments

  • @Jennifer McGarry

    Hey Jennifer, you also need an Authorization Token and pass that along in the header of the request that will at least allow you to hit the API endpoints.

    This is explained on the following page:

    b19a1563d8486a52ff3e4c1551cb9b6d-huge-im

    The authorization token is timestamped and only last for 1 hour (without refreshing) so some logic needs to be added for that.

    I have built a similar application to offload/backup the different entities from Blackbaud to a separate data store if you wish to discuss in more detail.

    I hope this helps and let me know if you have any questions.

  • @Bob Rowe

    Hey Bob, thank you for your response. I do understand that I need an auth token, I am just unsure how to get it in an automated(?) way using my job integration that I am creating. I do understand the oAuth process but every example I have seen seems to be a front end user talking to a backend and approving the connection manually to get the token.

    I need a way to do this in a job run hourly with no human intervention. I am just new to RE.

    Thanks!

  • @Jennifer McGarry:

    …every example I have seen seems to be a front end user talking to a backend and approving the connection manually to get the token.

    I need a way to do this in a job run hourly with no human intervention

    You are correct for the original token. But, you need to store that token (i.e. in a database). Blackbaud provides you with a “Refresh Token” as well. With the “Refresh Token”, you programmatically (i.e. C#, Javascript) need to request a new Auth Token after one hour of inactivity. Essentially, the auth token will continually change (for security).

    Automating this process needs to be done in code with a place to persist the Token/Refresh Token. I use tools and code (c#) in Azure to do this. Send me a private message (click on my name) and I can provide some additional info.

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 Raiser's Edge NXT Fall 2025 Product Update Briefing Badge

    @Jennifer McGarry
    As @Bob Rowe mentioned, have somewhere that store the API token and refresh token, but I would go 1 step further and store the API token and refresh's token's “time” info. Either you store the time you refresh, and then “add” # of seconds when the token expire (60 minutes) or refresh token expires (365 days) at your “routine” (mention below), or store the “date/time token/refresh token" expires directly.

    You will want to create a subroutine that:

    1. checks if the token has expired, if not, return the token for use
    2. if token expired, use the refresh token API endpoint to refresh the token (and make sure to NOT specify preserve_refresh_token, so you always get new refresh token with a new 365 days expiration), store the new token, refresh token and update the expiration

    Doubt this would be the case, but you MAY want to have a “scheduler” that calls this subroutine “potentially” monthly and if the refresh token will expire within the month, refresh it.

    Then in your application, all you need to do is call this subroutine to get a token for calling API. (Keep in mind that if your application runs “long” and may call API multiple times, that you “potentially” call the subroutine each time to get a token. Only you can determine how long your application/function will run for and determine if there's a possibility that the token expires in midst of operations. (there are other “condition” and logic you can applies to make the subroutine more efficient, but you can play around with that.

  • @Jennifer McGarry, I'll add a few comments in addition to what others have said on this thread…

    The SKY API operates in the context of an end-user (i.e., someone with access to log into Raiser's Edge). This is so that the system can enforce that user's security permissions (as defined by your organization's administrator). So if a user can't do <x> in the product, they won't be able to do <x> via the API. That's why the authorization protocol involves a human interaction - it needs a user to authenticate (via Blackbaud ID) and provide consent (aka authorization).

    The good news is it's a one-time chore and from there no further user interaction is required (since you can always use your refresh token to obtain a new access token, non-interactively). The access token is attached to the consenting user (and the SKY application in context) and thus can only do at most that which the user can do in the product. It's also subject to the "scope" defined for the application by the developer (meaning, the actual level of access for a token can be further scoped-down to less than the user's actual set of security permissions).

    So both access token (a 60-minute token) and refresh token (365 days, on a sliding window) are associated with an end-user. If you're building a headless application (like a job or a script or some other non-interactive system), you still need an end-user to provide that initial one-time consent. That could of course be *you* (i.e., you're acting as the developer AND an application user) if you yourself have permission to log into Raiser's Edge.

    If you haven't seen it, you might consider checking out the headless data sync article in the Showcase area of the developer portal. Another (easy) option you can explore is, use the technique I demonstrate in this video to obtain the initial access token and refresh token:
    https://www.youtube.com/watch?v=Dw3vrbSPAZU

    (skip to the 25:10 mark)

    This approach uses Postman for the initial one-time consent chore. Postman acts as your OAuth client (you plug in your SKY application's ID and secret), and it handles launching the browser, obtaining consent, etc. The end result is that you get access and refresh tokens associated with *your* end-user (Blackbaud ID) account. You can then store those values and use them going forward (for example, you could make APIs calls with the access token, or discard it altogether and just paste in the refresh token into your script so it refreshes the access token before making API calls). Keep in mind that the token will be operating in the context of *you* and thus subject to your permissions as granted by your organization's administrator.

    Hope this helps!

  • @Ben Lambert

    Thanks so much. This really made it clearer. However, now that I have the tokens needed I keep getting a 400 error and I am unsure which part of my request is wrong. Any idea?

    axios.request(
    {
    method: 'post',
    url: `${apiURL}`,
    // data: `grant_type=refresh_token&refresh_token=${apiRefreshToken}&preserve_refresh_token=true&client_id=${apiAcct}&client_secret=${apiPWSecret}`,
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    data: {
    grant_type: 'refresh_token',
    refresh_token: `${apiRefreshToken}`,
    preserve_refresh_token: true,
    client_id: `${apiAcct}`,
    client_secret: `${apiPWSecret}`,
    },
    })

    I tried sending the data in both formats and neither are working.

  • Alex Wong
    Alex Wong Community All-Star
    Ninth Anniversary Kudos 5 Facilitator 3 Raiser's Edge NXT Fall 2025 Product Update Briefing Badge

    @Jennifer McGarry
    this is what mine looks like and works every 58 minutes:

    0acf9cf6b8db8bfa9dd39163d46db3b2-huge-im
  • @Alex Wong @Ben Lambert @Bob Rowe

    Thank you all so much for your assistance with my issue. I am now successfully making the API call to refresh the token in an “automated” way in order to run my data sync.

    God Bless!