Bring Your Own API Key SaaS Enrichment: The Pattern
How I built a bring your own api key SaaS enrichment layer with multi-provider adapters, so customers pay their own lookup costs and I keep my margin.
By Mike Hodgen
The Per-Lookup Cost That Quietly Breaks Your Pricing
I built a sales tool that, among other things, enriches contacts. You feed it a name and a company, it hands back a verified work email, a phone number, a title, the decision-maker behind the buying signal. Useful stuff. But the moment I started designing the pricing, I hit a wall that anyone building a SaaS with enrichment runs into: the data costs money per lookup, and that cost is wildly uneven across customers.
This is where bring your own api key saas enrichment stops being a nerdy implementation detail and becomes the whole business model.
Why one vendor's cost shouldn't be in your price
Enrichment providers charge per lookup. A few cents here, a dime there, sometimes more for a verified phone number. Innocent at small scale. Brutal at volume.
So you have to decide: do you bake that cost into a flat monthly subscription? If you do, you're now guessing the average usage of every customer and pricing for the guess. The customer doing 50 lookups a month subsidizes nobody and feels overcharged. The customer doing 5,000 lookups a month quietly destroys your margin and feels like a genius.
There's no flat number that serves both. Someone always loses. It's the exact same math problem as metering AI usage by the credit, variable per-unit cost wrapped in a fixed price is a slow margin leak with a smile on it.
The customer who already pays for enrichment
Here's the part that really bothered me. A meaningful chunk of the customers I'd be selling to already have an enrichment account. They're already paying a provider directly.
If I roll that same cost into my subscription, I'm charging them twice for data they already buy. They notice. They resent it. And the savvy ones walk, because they can do the math.
That's the problem BYO-key solves. Let me define it properly.
What Bring Your Own API Key SaaS Enrichment Actually Means
Bring your own api key saas enrichment means the customer plugs their own enrichment provider key into my app, and every lookup hits their account and their billing. My software makes the call. I never pay for it.
The customer's spend flows through their account
The mechanics are simple. The customer pastes in their API key during setup. When my app needs to enrich a contact, it uses that key to authenticate the request. The provider bills the customer directly, on the customer's existing contract, at the customer's negotiated rate.
BYO-Key billing flow vs traditional baked-in pricing
My app orchestrates. The customer's account settles the bill. There is no per-lookup cost rolled into the subscription, because there is no per-lookup cost on my side at all.
Why this kills the lock-in objection
This is the reassurance a serious buyer is actually looking for at the bottom of the funnel. Two objections die at once.
First: surprise costs. There's no hidden enrichment markup buried in the monthly fee. The buyer sees exactly what my software costs and exactly what their data costs, separately, and they can reason about each.
Second: vendor lock-in. Because the data source is the customer's choice, I'm not welding them to one provider I happened to strike a deal with. They bring whichever provider they already trust. If they want to switch providers next quarter, they switch a key.
I keep the app provider-agnostic on purpose. I'm not in the data business. I'm in the orchestration business. That distinction shapes every design decision that follows, starting with the one piece of work that actually matters.
The Normalized Contact Shape Every Provider Maps To
Every enrichment provider returns a different mess. Different JSON structure, different field names, different ways of expressing confidence, different ideas about what a "phone number" even is. One returns email, another returns work_email, a third nests it three levels deep under a verification object.
If you let those differences leak into your application code, you've built a cage around one vendor. The whole point of multi-provider adapters without eating the cost is to never let that happen.
One internal contract, many APIs
The core design decision was to define one internal contact shape that the rest of the app speaks. Something like this:
Normalized contact shape mapping from multiple providers
full_namework_emailphonetitlecompanyconfidence(a normalized 0 to 1 score)source(which provider returned this)
That's the contract. Every part of my app that touches an enriched contact reads exactly these fields. Nothing else.
Each provider then gets an adapter whose only job is to translate that provider's raw response into this shape. Provider A's email_verification.address becomes work_email. Provider B's confidence_pct of 92 becomes confidence: 0.92. The app code never sees a provider-specific field, ever.
Why normalization is the real work
People think the hard part is calling the API. It isn't. Calling an API is a tutorial.
The durable value lives in the normalization layer. The translation, the confidence-score reconciliation, the handling of partial responses, deciding what null means versus what "we looked and found nothing" means. That's the part that takes judgment and the part that survives when you add provider number four.
The API call is rented. The abstraction is owned. Which is exactly the principle behind pay for primitives, build the logic, I rent the lookup, I own everything around it.
The Multi Vendor Adapter Pattern, Step by Step
Once you have a normalized contact shape, the architecture almost designs itself. This is the multi vendor adapter pattern, and it's the difference between a tool that ages well and one you rewrite every time a provider changes their pricing.
The adapter interface
Every adapter implements the same interface. One method matters:
Multi-vendor adapter pattern architecture
enrich(contact) -> normalized_result
You hand it a contact (name, company, whatever you've got). It returns the normalized shape from the last section, or a clean "not found." That's the entire promise the app depends on.
Inside that method, each adapter handles its own world:
- Authentication, how this provider expects the key (header, query param, bearer token)
- Rate limits, backing off when the provider says slow down
- Error mapping, translating the provider's 47 different error codes into a handful my app understands
- Quirks, the undocumented behavior every API has, contained in one file
Swapping providers without touching app logic
Because the app only ever calls enrich(), it has no idea which provider is behind it. The calling code is identical whether it's provider A, B, or one that doesn't exist yet.
That means swapping providers is a configuration change, not a code change. The customer points at a different adapter. Nothing in the application logic moves.
Adding a new provider is one file
This is the payoff that makes the pattern worth the discipline. When I want to support a new enrichment provider, I write one new adapter file. It implements enrich(), handles its own auth and quirks, maps its response to the normalized shape, and it's done.
No changes to the calling code. No regression risk in the parts of the app that were already working. The new provider slots in next to the others and the rest of the system never notices.
I've built this exact shape across more than fifteen AI systems now. The pattern doesn't care if the primitive is enrichment, an LLM, or an image model, rent the primitive, own the interface, and adding the next vendor stays cheap forever.
Failover and Comparison: The Bonus You Get for Free
Here's the part I didn't plan for and ended up loving. Once you have a normalized interface in front of every provider, multi-provider behavior becomes nearly free. You built it for margin and got quality features as a side effect.
When one provider returns nothing
Enrichment whiffs constantly. A provider that's great for tech companies is mediocre for local trades. A provider with deep US coverage is thin in Europe.
Failover flow between providers
With the adapter pattern, failover is trivial. If provider A returns no email, the app calls provider B with the same normalized request and the same normalized response coming back. Real example from testing: I ran a lookup on a mid-market operations director where the first provider returned nothing, a dead end. The second provider returned a verified work email with a 0.94 confidence score. Same contact, same code path, different adapter.
That failover is impossible if your code is welded to one vendor's API. You'd have a special case bolted onto a special case, and it would rot.
Letting customers compare sources
If a customer has two provider keys, I can query both and keep the higher-confidence result. The normalized confidence and source fields make that a simple comparison, not a custom integration.
This turns a margin decision into a quality feature. The customer isn't just avoiding double-billing. They're getting better data because the tool can shop across the providers they already pay for.
Honest caveat: running multiple providers per lookup costs the customer more, because it's two lookups, two charges. So this is opt-in, never the default. The customer decides when coverage matters more than cost. I just make the choice available instead of making it for them.
Storing Customer Keys Without Becoming a Liability
Let me be straight about the cost of this pattern, because it isn't free. The moment a customer hands you their enrichment key, you're holding a third-party credential that can spend their money. That's a responsibility, not a feature.
Encrypt at rest, scope tightly
The non-negotiables:
- Encrypt keys at rest. A key sitting in plaintext in your database is a breach waiting to be embarrassing.
- Never log them. Keys leak through logs more often than through databases. Scrub them at the boundary.
- Scope access by tenant. One customer must never be able to read another customer's key. This is table-stakes multi-tenancy, but enrichment keys raise the stakes because they're someone else's money.
None of this is exotic. It's the discipline of treating a credential like a credential instead of like a config value.
Validate the key before you trust it
Here's a small thing that saves a lot of support pain. When a customer saves their key, validate it immediately with a cheap test call.
If they fat-fingered a character, they find out during setup, not mid-campaign when 300 lookups silently fail. That one validation call has prevented more frustrated support tickets than any feature I built on top of it.
The honest limitation: BYO-key adds an onboarding step and a support surface. Some customers will fumble the setup, paste the wrong key, or not have an account at all. You're trading a frictionless signup for a margin-safe business. For the kind of tool I'm describing, that trade is worth it every time. Subsidizing heavy users' lookups out of a flat fee is a much worse problem to have.
When BYO-Key Is Right and When It Isn't
I don't think bring your own api key saas enrichment is the answer for every product. It's the right answer for a specific shape of business, and knowing the difference is the whole job.
Good fit: variable, high-volume, cost-sensitive usage
BYO-key wins when:
- Per-unit cost is real and variable. If your customers' usage swings from 50 to 5,000 lookups, no flat price works, and metering it yourself means becoming a billing company on top of a software company.
- Customers already own accounts. When a chunk of your market already pays a provider, BYO-key turns double-billing into a selling point.
- You want to stay vendor-agnostic. When you'd rather not bet your roadmap on one provider's pricing or survival.
This is the world the enrichment layer in the sales tool I built to replace five SaaS subscriptions lives in. Variable usage, cost-sensitive buyers, no appetite for lock-in.
Bad fit: zero-config consumer tools
BYO-key is the wrong call for a zero-friction consumer product. If your conversion depends on someone going from landing page to value in 60 seconds, asking them to go create a third-party account and paste in a key will kill you. Every setup step you add costs conversions you can't afford. In that world, you eat the cost, price for it, and hide the complexity.
When BYO-key fits and when it doesn't
The pattern isn't good or bad. It fits a margin profile or it doesn't.
This is the kind of decision I make when I build sales and ops tools, margin-aware, lock-in-free, designed around how the cost actually behaves instead of around a pricing page that looks tidy. Not a slide deck about AI strategy. The actual build. If you're weighing what an enrichment or sales tool should look like for your business, that's a conversation worth having.
Ready to bring AI leadership into your company?
I work with a small number of companies at a time. If you're serious about AI, apply to work together and I'll review your application personally.
Get AI insights for business leaders
Practical AI strategy from someone who built the systems — not just studied them. No spam, no fluff.
Ready to automate your growth?
Book a free 30-minute strategy call with Hodgen.AI.
Book a Strategy Call