{{ message }}
Repository navigation
feat(raisersedge): add Blackbaud Raiser's Edge NXT (SKY API) API module - #227
Open
seanspeaks wants to merge 1 commit into
Open
seanspeaks wants to merge 1 commit into
seanspeaks wants to merge 1 commit into
Conversation
Port Left Hook-cleared Raiser's Edge NXT module into Frigg v2 shape under packages/v1-ready/raisersedge: OAuth2 SKY client, definition, OpenAPI, capability manifest, ADR-057 Contact/Company mappings (UNVALIDATED), SKY Add-ins Fenestra draft, and HubSpot-style webhook extension. Co-authored-by: Sean Matthews <sean.matthews@lefthook.co>
seanspeaks
marked this pull request as ready for review
October 22, 2026 00:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Add a Frigg v2 API module at
packages/v1-ready/raisersedge(@friggframework/api-module-raisersedge@1.0.0), shaped likepackages/v1-ready/fathom/with HubSpot-styleextensions/webhooks/.Port source: Left Hook–owned Raiser's Edge NXT module (Sean-cleared
raisersedge.tar.gzfromlefthookhq/aes--frigg@d6dc4bd…, pathbackend/src/api-modules/raisersedge) — genericApi+Definition. Client-specific coupling (e.g. AES description text,REDIRECT_URI/raisersedge) stripped. No client mocks/sample data; minimal offline fixtures only.No prior package existed under
packages/(neitherv1-readynorneeds-updating); this is a greenfield add.What the API is / sources
Blackbaud Raiser's Edge NXT via the SKY API (REST) — constituents, gifts, events, fundraising funds/appeals, and webhook subscriptions. Official OpenAPI is not published as a single downloadable document for the full surface;
raisersedge.openapi.yamlis a curated subset verified against the interactive docs.Auth
https://oauth2.sky.blackbaud.com/authorizationhttps://oauth2.sky.blackbaud.com/tokenhttps://api.sky.blackbaud.comAuthorization: Bearer …,Bb-Api-Subscription-KeyRAISERSEDGE_REDIRECT_URIBLACKBAUD_CONSUMER_KEY,BLACKBAUD_CONSUMER_SECRET,BLACKBAUD_SCOPE,BLACKBAUD_SUBSCRIPTION_KEYscope(documented Blackbaud shape)refresh_token_expires_in→refreshTokenExpire; persistsenvironment_idmd5(environment_id)as entity/credentialexternalIdEndpoints covered
listConstituents,getConstituent,createConstituent,updateConstituent,duplicateSearchConstituents, email/phone/address list/create/update, type/title listslistGifts,getGift,createGift,updateGift(sendsIf-Match: *)listEvents,getEvent,createEvent,updateEvent, participant list/create/updatelistFunds,listAppealscreateSubscription,getSubscription,deleteSubscriptionSkipped
SubscriptionDeletedEvent— list-all not confirmed on developer.blackbaud.com for this PR)Capability manifest
raisersedge.capabilities.json—capability-manifest/v0.1, version 1.0.0. Objects: constituent, gift, event, fund, appeal, subscription. Every capabilitymethodexists onApi(asserted intests/spec-sync.test.js).Canonical mappings (ADR-057) — UNVALIDATED
Via
extensions.mapping→business@1:mappings/contact.js— Individual constituent → Contactmappings/company.js— Organization constituent → CompanyNo Deal / support@1 / billing@1 mappings. Gifts, events, funds, and appeals do not fit existing canonical schemas without inventing semantics (gifts ≠ deals). Called out per ADR-057.
Fenestra
Draft included:
raisersedge.fenestra.yaml— Blackbaud SKY Add-ins (iframe tiles, page actions, full pages) with@blackbaud/sky-addin-client.Validated with
node fenestra.js validatefrom branchclaude/fenestra-spec-draft-Q367t.Webhooks extension
extensions/webhooks/(Tier 3,useDatabase: false):OPTIONS /webhooks— CloudEvents Abuse Protection (WebHook-Allowed-Origin: eventgrid.azure.net)POST /webhooks— optional?webhookKey=check →RAISERSEDGE_WEBHOOK_RESOLVE→RAISERSEDGE_WEBHOOKenvironment_id(or hashed externalId) / persisted subscription idsPattern from HubSpot. Blackbaud does not document an HMAC signature header; shared secret on the webhook URL is the documented pattern.
Proof
npm test(module) — PASSIncludes
spec-sync, mapping, and webhook extension tests.Screenshot / terminal capture:
raisersedge npm test pass
Full log:
/opt/cursor/artifacts/raisersedge-npm-test.txtFenestra:
/opt/cursor/artifacts/raisersedge-fenestra-validate.txtValidate notes:
/opt/cursor/artifacts/raisersedge-frigg-validate.txtfrigg validate/ definition schema — partialfrigg validateonfriggframework/friggbranchfeat/frigg-validatetargets an app Definition (ADR-051), not a standalone api-module. Not run against a Frigg app here.validateApiModuleDefinition()from@friggframework/schemason that branch:packages/schemas/tests)modelName,mappings,getAuthorizationRequirements, live functions) — schema lag vs. runtime convention / sibling modules; recorded as an open question.frigg auth test .— pending credentialsNo Blackbaud SKY sandbox OAuth client /
RAISERSEDGE_REDIRECT_URI/ subscription key in this environment. Do not fake it.Prior work credited
packages/v1-ready/fathom/packages/v1-ready/hubspot/extensions/webhooks/friggframework/friggdocsclaude/fenestra-spec-draft-Q367tOpen questions
api-module-definition.schema.jsonallowmodelName,mappings,getAuthorizationRequirements, and live function values (not{ type: 'function' }descriptors)?SubscriptionDeletedEvent.oauth2.sky.blackbaud.com/authorizationvs. newer SPA authorize URL shown asauthorization_spain docs (clipboard values not extractable from the rendered page)?BLACKBAUD_SCOPEset for marketplace apps (rnxt.r rnxt.w rnxt.d rnxt.whkappears in auth tutorial samples) — leave unset and require env?environment_idacross all event types — hosts may need to overrideextractRoutingHintsif some types only carry subscription id.To show artifacts inline, enable in settings.