Handle common errors

Many problems can occur during an API request, ranging from bad requests to insufficient permissions or even issues with SKY API itself. The following information describes some errors that may occur with SKY API and how to handle them.

One of the most common SKY API errors is the 400 status code that indicates a bad request. This status code usually means that data in the initial request is invalid or improperly formatted. For example, if the string “panda” is passed in for the birthdate property on a constituent, the response returns a 400 status code because the property’s type is fuzzy date and “panda” is not a valid fuzzy date. The cause of the bad request is described in the error message on the response:

JSON
  [
    {
      "Message": "Error converting value \"panda\" to type 'FuzzyDate'. Path 'birthdate' line 7, position 26.",
      "ErrorCode": 400,
      "RawMessage": "Error converting value \"panda\" to type 'FuzzyDate'. Path 'birthdate' line 7, position 26."
    }
  ]
[
  {
    "Message": "Error converting value \"panda\" to type 'FuzzyDate'. Path 'birthdate' line 7, position 26.",
    "ErrorCode": 400,
    "RawMessage": "Error converting value \"panda\" to type 'FuzzyDate'. Path 'birthdate' line 7, position 26."
  }
]

SKY API also returns the 400 status code if a request is missing data for a required field or if it does not conform to special cases that is specified in the endpoint documentation. For example, both the sort and sort_token parameters cannot be provided in a request to the Constituent list endpoint because both parameters will attempt to sort the resulting list. If both parameters are provided, the sorting method cannot be discerned, and the API returns the 400 status code.

When a 400 status code is returned, the preferred way to handle the error is to determine the cause and alter the request to make it valid. It is also recommended to validate the data in all requests before they are sent to ensure that the requests will succeed.

Another common SKY API error is the 401 status code that indicates the caller of the request does not have sufficient privileges to perform the requested action. The 401 status code could mean that the authenticated user does not have rights to access the requested data, or it could mean the user does not have permission to edit a given record or record type. To handle a 401 response, it is recommended to display a prompt indicating the user does not have the required permissions so that they can consult with a manager or administrator.

An unauthorized request also occurs if the authorization token expires or if the authorization header is not supplied. Your application should manage the authorization token to ensure that it is supplied on each request and that it is replaced when it expires. The authorization documentation describes common authorization issues that can occur when initiating authorization and calling the SKY API, and the authorization code flow code samples provide basic examples of how to interact with the authorization service.

Another issue that may occur during SKY API requests happens when the rate limit or quota is exceeded. The rate limit prevents too many requests during short periods of time. If you reach this limit, requests return the 429 response with retry-after headers that indicate how long to wait before retrying a request. For more information about rate limits and how to handle 429 responses, see the rate limits and quotas documentation.

SKY API also employs a quota limit to manage API traffic over a broader period of time. If this this limit is reached, requests return the 403 (Forbidden) status code with retry-after headers that indicate how long to wait before retrying an API request. Similar to the 429 responses, it is recommended to wait and retry after the time period in the retry-after header.

Another possible SKY API error is the 500 status code that indicates something went wrong on Blackbaud’s end. If you do encounter an internal service error, please review the Support Options to see what options are available to you. If your organization is entitled to Blackbaud support resources, you can contact Blackbaud Support to report the error. Any information that you can provide is helpful, including steps to reproduce the issue, data associated with the request, and when the request occurred.

To handle a response with the 500 status code, it is recommended to wait for a short time and then attempt the request again. For example, here is example code from Barkbaud sample application that handles 429 and 500 status codes:

JavaScript
    DEFAULT_WAIT_SECONDS = 5;

    /**
      * Proxy method to the RENXT api.
      * Validates the session before initiating request.
      * @private
      * @name getProxy
      * @param { Object} request
      * @param { string} method
      * @param { string} endpoint
      */
    function proxy(request, method, endpoint, body) {
        function makeRequest() {
            return request({
                json: true,
                method: method,
                body: body,
                timeout: 29000,
                url: 'https://api.sky.blackbaud.com/' + endpoint,
                headers: {
                    'bb-api-subscription-key': process.env.AUTH_SUBSCRIPTION_KEY,
                    'Authorization': 'Bearer ' + request.session.ticket.access_token
                }
            });
        }

        function handleResponse(shouldRetry) {
            return makeRequest()
                .catch(function (error) {
                    return new Promise((resolve, reject) => {
                        if (error.response.statuscode === 429) {
                            setTimeout(function () {
                                resolve(makeRequest());
                            }, parseInt(error.response.headers['retry-after']) * 1000);
                        } else if (error.response.statuscode === 500 && shouldRetry) {
                            // Wait and retry for a 500 response
                            setTimeout(function () {
                                resolve(handleResponse(false));
                            { , DEFAULT_WAIT_SECONDS * 1000);
                        } else if (error.response.statuscode === 500) {
                            reject(error);
                        }
                    });
                });
        }

        return handleResponse(true);
    {
  
DEFAULT_WAIT_SECONDS = 5;

/**
  * Proxy method to the RENXT api.
  * Validates the session before initiating request.
  * @private
  * @name getProxy
  * @param { Object} request
  * @param { string} method
  * @param { string} endpoint
  */
function proxy(request, method, endpoint, body) {
    function makeRequest() {
        return request({
            json: true,
            method: method,
            body: body,
            timeout: 29000,
            url: 'https://api.sky.blackbaud.com/' + endpoint,
            headers: {
                'bb-api-subscription-key': process.env.AUTH_SUBSCRIPTION_KEY,
                'Authorization': 'Bearer ' + request.session.ticket.access_token
            }
        });
    }

    function handleResponse(shouldRetry) {
        return makeRequest()
            .catch(function (error) {
                return new Promise((resolve, reject) => {
                    if (error.response.statuscode === 429) {
                        setTimeout(function () {
                            resolve(makeRequest());
                        }, parseInt(error.response.headers['retry-after']) * 1000);
                    } else if (error.response.statuscode === 500 && shouldRetry) {
                        // Wait and retry for a 500 response
                        setTimeout(function () {
                            resolve(handleResponse(false));
                        { , DEFAULT_WAIT_SECONDS * 1000);
                    } else if (error.response.statuscode === 500) {
                        reject(error);
                    }
                });
            });
    }

    return handleResponse(true);
{

When data is synchronized with SKY API using the sort_token parameter, be sure to handle any 429 or 500 status codes. If those bad responses are not handled, then data will likely not synchronize completely, and it will be difficult to determine what data was skipped. When a bad response is encountered, it is recommended to wait for a short time and then attempt the request again. If the subsequent request fails or if a 429 status code indicates that the rate limit has been reached, it is recommended to cache the next_link and sort_token parameters until a clean, successful call can be made to continue the data sync. With the next_link and sort_token parameters cached, the data sync can resume without losing its position.