{"id":275,"date":"2024-04-05T01:51:09","date_gmt":"2024-04-05T01:51:09","guid":{"rendered":"https:\/\/duff.io\/?p=275"},"modified":"2024-04-05T11:55:38","modified_gmt":"2024-04-05T11:55:38","slug":"my-process-to-programming-with-blackbaud-sky-api-and-really-any-api","status":"publish","type":"post","link":"https:\/\/duff.io\/?p=275","title":{"rendered":"My process to programming with Blackbaud Sky API (and really any API)"},"content":{"rendered":"\n<p>In preparing for the panel session &#8220;APIs and the Art of the Possible&#8221; for the <a href=\"https:\/\/theatlis.org\/page\/annual-conference-2024\">2024 ATLIS Conference<\/a>, I spent some time thinking about my process for developing solutions using APIs. I have recently been working on something to send gift acknowledgment letters via Google based on data in Blackbaud Raiser&#8217;s Edge and thought it might make a practical case study. So here it goes:<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Overview<\/h4>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Meet<\/strong> with key stakeholders to understand what the problem\/need is.<\/li>\n\n\n\n<li><strong>Identify<\/strong> the Minimum Viable Product (MVP) to use as a starting point from which to iterate. This serves as a proof of concept and provides a feedback loop to develop the solution.<\/li>\n\n\n\n<li><strong>Explore<\/strong> the API via documentation\/tools to see what it can provide for our needs. Manually run the API calls I plan to verify that they provide the needed data.<\/li>\n\n\n\n<li><strong>Deconstruct<\/strong> the problem into pieces and start implementing and iterating.<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Meeting with Key Stakeholders<\/h4>\n\n\n\n<p>Here are some questions I might ask the key stakeholders:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Can you demonstrate to me how the current process works?<\/li>\n\n\n\n<li>What works well for you?<\/li>\n\n\n\n<li>What frustrates you?<\/li>\n<\/ul>\n\n\n\n<p>I&#8217;ll want to drill down and understand the most common cases where there might be weird exceptions and figure out where (and if) technology can help. I also try to understand the goals they are trying to achieve. Perhaps an entirely different process could do a better job of meeting those goals.<\/p>\n\n\n\n<p>For the gift acknowledgment letters, I met with the member of our team who generates them. She is also our Raiser&#8217;s Edge expert and understands the underlying data. Due to some security changes in the hosting environment, the previous method of generating letters didn&#8217;t work. The new process was more convoluted and frustrating. It was also more complicated than I thought since different gifts had different acknowledgment letters, which could be in different formats (e-mail vs print).<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">The Minimum Viable Product (MVP) &amp; Deconstruction<\/h4>\n\n\n\n<p>It&#8217;s easier to build and test little pieces of a project rather than build everything all at once. For the gift acknowledgments, the MVP was code that grabbed all unacknowledged gifts and placed them into a spreadsheet.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"151\" src=\"https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-1024x151.png\" alt=\"\" class=\"wp-image-286\" srcset=\"https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-1024x151.png 1024w, https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-300x44.png 300w, https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-768x113.png 768w, https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-1536x226.png 1536w, https:\/\/duff.io\/wp-content\/uploads\/2024\/04\/image-2048x302.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Even this simple project is useful; I can use Google Add-ons like <a href=\"https:\/\/yamm.com\">Yet Another Mail Merge<\/a> or <a href=\"https:\/\/workspace.google.com\/marketplace\/app\/autocrat\/539341275670\">Autocrat<\/a> to send the acknowledgment letters based off of this spreadsheet.<\/p>\n\n\n\n<p>The MVP allows me to get user and recipient feedback and discover any surprises in the data\/process. For example, what should I do with a gift that doesn&#8217;t have an acknowledgment letter assigned to it?<\/p>\n\n\n\n<p>After getting feedback, the next step might be to write code to merge the letters into a Google Doc, which could be printed or emailed. After another feedback loop, I might automate the email generation and\/or make the solution an add-on for Raiser&#8217;s Edge or Google Workspace.<\/p>\n\n\n\n<p>Building incrementally and iterating allows me to learn and adapt before I spend a ton of time doing development work.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Exploring the API &amp; Deconstructing the Problem<\/h4>\n\n\n\n<p>Before writing any code, I want to figure out what API calls I need to make, how I use the endpoints, and what results I should expect. I start by going to the API documentation, so for a Blackbaud product, I would start at <a href=\"https:\/\/developer.blackbaud.com\">https:\/\/developer.blackbaud.com<\/a> and browse through to the <a href=\"https:\/\/developer.sky.blackbaud.com\/api#api=58bdd5edd7dcde06046081d6&amp;operation=GetOrCreateGiftCustomFieldCategory\">Raiser&#8217;s Edge NXT endpoints<\/a>. To start, I want a way of finding all unacknowledged gifts so I would look at endpoints involving gifts.<\/p>\n\n\n\n<p><img decoding=\"async\" width=\"637px;\" height=\"443px;\" src=\"https:\/\/lh7-us.googleusercontent.com\/Dc3uDvVP2X-440F1fH83WfbRpQeWi9EHOEOZL6oVSIjlzzT3kxjOKxa9KEO04YyHpUwA31qRPEArZprxQSLBPGfFbDzoXGJ_4DuK2RcC4ZM1Ee5rhQvZtvr6tUY-o2c3oYVXi35rH9VHXOa5V6SGbpFi0w=nw\" border=\"1\"><\/p>\n\n\n\n<p>In the documentation, we see an endpoint <a href=\"https:\/\/developer.sky.blackbaud.com\/api#api=58bdd5edd7dcde06046081d6&amp;operation=ListGifts\">GET Gift list<\/a> that returns a paginated list of gifts that match various criteria. The Blackbaud documentation has a handy tool we can test API calls with, by clicking on the green &#8220;Try It&#8221; button to launch the Sky API console (which requires being <a href=\"https:\/\/developer.blackbaud.com\/skyapi\/docs\/basics#activating-the-sky-api-console\">activated<\/a> prior to use).<\/p>\n\n\n\n<p><img decoding=\"async\" width=\"714px;\" height=\"483px;\" src=\"https:\/\/lh7-us.googleusercontent.com\/-3YCBxk_j7P-xj3kl1VXwLSNgSVFTq_b2-ZiDIyDoFt9L2LwZZumYc3anzDrTJajTSLFnzX6dZ9H8p-j93IFRzlwcDN9pyAgEOJDQnpg3fdFqUSy3jH1FHRTQQ7vajfUl0FccFwSH9WzGJX2E4eKgZhAsg=nw\" border=\"1\"><\/p>\n\n\n\n<p>Experimenting with the various parameters, I learned that it is probably helpful to use &#8220;date_added&#8221; to list only recent gifts. Between the documentation and some experimentation, I saw that &#8220;date_added&#8221; needed to be in <a href=\"https:\/\/datatracker.ietf.org\/doc\/html\/rfc3339\">RFC3339<\/a> format.<\/p>\n\n\n\n<p>There is also a parameter for &#8220;acknowledgement_status&#8221; which I can use to filter for only unacknowledged gifts. Using the SKY API console, I can look at a gift I know isn&#8217;t acknowledged and see that the status of &#8220;NotAcknowledged&#8221; is used.<\/p>\n\n\n\n<p>Now that I know what API call to use unacknowledged gifts I can review the information the API call returns about the gift. Looking at the gift letter templates, I noticed a lot of information I needed isn&#8217;t in the results, such as the &#8220;Acknowledgement Letter&#8221; (used to determine the template) and information about the constituent who gave the gift (like their name). Looking at RE NXT we see this data is associated with the gift:<\/p>\n\n\n\n<p><img decoding=\"async\" width=\"686px;\" height=\"424px;\" src=\"https:\/\/lh7-us.googleusercontent.com\/2WP6m99LgIRrP-p2wYhE-UiQrZIhJeubLzyhjod0ObUYpLckWV7EszE0EX-ibK3pc8AqjIpDFJDbf-21rygbIPAkoUXSxyZBehhmFcTy_o1cCb3e-Vpt3x4xB7t6eJN3NcqzGOA01Bz3a8ruTAbvRMwvIA=nw\" border=\"1\"><\/p>\n\n\n\n<p>More experimentation finds that <a href=\"https:\/\/developer.sky.blackbaud.com\/api#api=58bdd5edd7dcde06046081d6&amp;operation=GetGift\">GET Gift<\/a> returns more detailed information about a single gift, including the gift_letter, which is the &#8220;Acknowledgement letter&#8221; and that <a href=\"https:\/\/developer.sky.blackbaud.com\/api#api=56b76470069a0509c8f1c5b3&amp;operation=GetConstituent\">GET Constituent<\/a> provides information about constituent who gave the gift. <\/p>\n\n\n\n<p>With these three API calls we can get all of the information we need to acknowledge the letter.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Next Steps<\/h4>\n\n\n\n<p>With an understanding of the problem, identifying an MVP as a starting point, and knowing the API calls and parameters that get me the data I need, I can start coding. <\/p>\n\n\n\n<p>In reality, I didn&#8217;t have the time to develop the MVP, so I reached out to Kevin Harig at <a href=\"https:\/\/www.trabanttech.com\">Trabant Technology Partners<\/a>, who I&#8217;ve worked with in the past and who has done a lot of API work and had him build it.<\/p>\n\n\n\n<p>It&#8217;s also worth noting that <a href=\"https:\/\/docs.blackbaud.com\/microsoft-connectors-docs\/microsoft-power-platform\/power-automate\/acknowledgement-tutorial\/acknowledgement-webview\">Blackbaud has an excellent tutorial on using Power Automate to create gift acknowledgment letters<\/a> which provides a low-code way of solving the problem in a Microsoft environment. <\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In preparing for the panel session &#8220;APIs and the Art of the Possible&#8221; for the 2024 ATLIS Conference, I spent some time thinking about my process for developing solutions using APIs. I have recently been working on something to send gift acknowledgment letters via Google based on data in Blackbaud Raiser&#8217;s Edge and thought it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3,23,21,7],"tags":[],"class_list":["post-275","post","type-post","status-publish","format-standard","hentry","category-blackbaudk12","category-google-apps-script","category-google-workspace","category-programing"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/275","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=275"}],"version-history":[{"count":14,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/275\/revisions"}],"predecessor-version":[{"id":295,"href":"https:\/\/duff.io\/index.php?rest_route=\/wp\/v2\/posts\/275\/revisions\/295"}],"wp:attachment":[{"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=275"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=275"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/duff.io\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=275"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}