When we first started rebuilding Importacular for the Web view version of Raiser’s Edge, I had high hopes. The SKY API was fresh, well-documented, and seemed to have learned from the inconsistencies of the legacy COM API. After 25 years of working with Raiser’s Edge, I was ready for something cleaner.
What I didn’t expect was that we’d end up using three different methods to work with something as fundamental as code tables (what other applications sensibly call dropdown values). Let me explain.
Method 1: The Dedicated Endpoint (The Good Old Days)
When we started with the Constituent API, things were straightforward. Need to get a list of titles? There was a dedicated endpoint for that. It returned all available titles, and when creating a constituent, you just used the text value. Simple. Elegant. Just what I’d hoped for.
GET /constituent/v1/titles
Returns: ["Mr", "Mrs", "Ms", "Dr", ...]
When creating a constituent, you’d just set you title to the value of, say “Dr”:
Method 2: The Missing Endpoint (When Reality Sets In)
Then we hit ethnicity. There’s no dedicated endpoint for ethnicity values. Suddenly, the clean pattern broke down. We needed to call the Code Table API instead, but this required knowing either the name or ID of the code table itself.
Fortunately, having worked with the COM API for so many years, I knew the table ID from the database view. But this highlighted a problem: you now needed institutional knowledge that shouldn’t be necessary. New developers coming to the platform wouldn’t have this context.
GET /codetable/v1/codetableentries/{table_id}
It worked, but it felt like a step backwards. Why did titles get their own endpoint but ethnicity didn’t?
Method 3: The Query Challenge (When Everything Changes Again)
Then came Query. We started using the Query module and corresponding API to help look up records, and it’s genuinely fantastic – far more flexible than using regular endpoints with search parameters. But here’s the kicker: if we wanted to filter records using a code table entry, we no longer needed the text value. We needed the ID for that table entry.
For example, if you want to find a match on an existing individual, you might look them up by first name, surname and title. To do this effectively in Query, you need the title ID, not the text value “Dr”.
So back to the Code Table API we went, but this time extracting the ID instead of the text value.
This is where it gets absurd. The same code table value now required different data depending on which API you were calling:
- Creating a constituent with a title? Use the text value.
- Filtering a query by title? Use the ID.
- Looking up a code table? You need to know the table ID first (unless you want to enumerate all tables).
Three different ways to work with what should be a consistent concept.
Why This Matters
When the SKY API first launched, I was genuinely excited. The COM API had become unwieldy precisely because so many different people had worked on it over the years with no consistency. The documentation – what little there was – often came from the community (a lot of it written by me, right here on re-decoded.com).
SKY API was supposed to be different. The documentation is much better, I’ll give them that. But I fear it may be heading down the same path. Even the excellent documentation can’t fully compensate for these kinds of inconsistencies.
And Query? Don’t get me started. To use Query effectively, you need knowledge of the COM API that the majority of modern developers simply wouldn’t have. That’s a barrier to entry that shouldn’t exist for a REST API in 2026.
The Silver Lining
Thankfully, having worked with Raiser’s Edge for 25 years, I recognised some of the legacy patterns and was able to extrapolate them into our modern Importacular application. Those years of accumulated tribal knowledge meant we could navigate these quirks.
But that’s not really a solution, is it? An API shouldn’t require a PhD in its predecessor to use effectively.
What I’d Like to See
Ideally, working with code tables should be consistent:
- One way to get code table values – whether through dedicated endpoints for common tables or a single unified Code Table API for everything
- Consistent data format – if I get a title as “Dr”, I should be able to use “Dr” everywhere, not switch between text values and IDs depending on the context
- No prerequisite knowledge – developers shouldn’t need to know legacy table IDs or have worked with the COM API to be effective
I’m not suggesting this is an easy problem to solve. I appreciate the technical constraints and backward compatibility concerns. But these are the kinds of inconsistencies that compound over time and create the very problems SKY API was meant to avoid.
For Now, We Work Around It
In Importacular, we’ve built abstractions to handle all three methods. Our code knows when to fetch text values, when to fetch IDs, and how to navigate the Code Table API when dedicated endpoints don’t exist. It works, and our users don’t see the complexity.
But every time I add another conditional branch to handle yet another edge case, I think about what could have been.
If you’re building with SKY API and hit these same code table inconsistencies, you’re not alone. Check the community forums, and know that with a bit of patience (and maybe 25 years of Raiser’s Edge experience), you’ll figure it out.
And Blackbaud, if you’re reading this: I still have faith. The platform is moving in the right direction. Let’s just make sure we don’t recreate the same consistency problems we were trying to escape.