PATTERN Cited by 1 source
Vendor abstraction service layer¶
When to use¶
You have:
- A dependency on a particular third-party vendor for some capability your platform consumes.
- A reasonable expectation that you may want to swap, add, or combine vendors later — for cost, capability, regulatory, or strategic reasons.
- The vendor has opinionated quirks (auth flow, rate limits, batch sizes, payload schema, workspace identifiers, webhook formats) that you don't want leaking into the rest of your platform.
The pattern¶
Build a dedicated service whose primary responsibility is mediating between platform code and the third-party vendor. Everything platform-side that wants to talk to the vendor talks to this service instead. The service:
- Exposes a vendor-neutral domain API to the rest of the platform.
- Translates that API into vendor-specific calls.
- Owns the vendor's auth credentials, rate-limit awareness, retry/idempotency policy, and error-mapping.
- Is the only place that can be ripped out and replaced when the vendor changes.
The architectural goal: keep the rest of the platform vendor-shape-agnostic so a vendor swap is a one-service rewrite, not a platform-wide refactor.
Canonical instance — Instacart CRM Service¶
Verbatim from the 2026-05-14 source (sources/2026-05-14-instacart-scaling-personalized-marketing-for-multi-tenant-commerce-platforms):
"This service isolates provider-specific behavior behind a clean abstraction layer. That gives us flexibility to change providers in the future, support multiple providers at once, and avoid tightly coupling our core platform to any one vendor."
The CRM Service is the canonical instance. It:
- Owns vendor knowledge: workspace identifiers, batch-API shape (≤50 users per call), per-retailer rate limits, auth.
- Translates platform shapes to vendor shapes: incoming per-batch personalization request → vendor's specific batch- send API payload + per-retailer workspace targeting.
- Owns idempotency policy at the at-least-once-streaming boundary so the rest of the platform doesn't need to care.
- Is the only platform service that imports the vendor's SDK or schema.
The three goals named verbatim — change providers in the future, support multiple providers at once, avoid tightly coupling to any one vendor — define the pattern's success criteria.
Sibling patterns on the wiki¶
The wiki has other instances of the same architectural instinct, applied to different verticals:
- patterns/ai-gateway-provider-abstraction — LLM provider abstraction (OpenAI / Anthropic / Bedrock / in-house). The AI gateway exposes a vendor-neutral inference API and routes per request to the right provider.
- patterns/connector-library-as-protocol-abstraction — Unity Catalog's connector library that abstracts engine- specific commit semantics behind a clean engine ↔ catalog protocol so engines don't have to care whether the catalog is UC, Polaris, or HMS.
All three share the same shape: isolate the vendor's specific behavior behind one service, keep the rest of the platform vendor-agnostic, treat vendor neutrality as a first-class architectural goal.
Distinct from anti-corruption layer¶
DDD's anti-corruption layer is similar in mechanism but different in motivation. ACL exists to prevent a legacy system's vocabulary from polluting a new system. Vendor abstraction service layer exists to preserve future optionality — you may not even know yet that you'll swap the vendor; you build the layer because the option is cheap to keep open and expensive to retrofit.
What the layer typically encapsulates¶
| Vendor concern | Platform concern |
|---|---|
| Auth scheme (OAuth, API keys, SAML) | Plain "send a message to user X" |
| Workspace identifiers, account IDs | Tenant ID |
| Rate-limit headers + retry rules | Backpressure / queueing strategy |
| Batch-size limits, payload format | Domain object (campaign, shipment) |
| Webhook callback URLs | Event/state transition |
| Vendor-specific error codes | Domain error categories |
| SDK / HTTP client lifecycle | Service-method signature |
The platform's domain model stays clean; the vendor's quirks all live behind one boundary.
Caveats and tradeoffs¶
- Lowest-common-denominator API. The vendor-neutral API can only expose features that all candidate vendors support — or it has to expose vendor-specific extensions, which leak the abstraction.
- Performance overhead. The translation layer adds latency
- serialization cost. Usually negligible vs the vendor's own API latency, but measurable.
- The layer can become its own legacy. If the vendor- neutral API is over-designed for hypothetical multi-vendor futures that never come, the layer is just complexity.
- Doesn't solve data lock-in. Workspaces, customer lists, templates inside the vendor are still non-portable; abstraction at the API layer doesn't help with vendor state. See patterns/per-tenant-workspace-in-third-party-saas for the data-portability tradeoff.
When NOT to use¶
- The vendor is part of your unique value proposition (e.g. your platform sells "powered by Stripe" — abstracting that hides the value).
- The vendor relationship is stable for foreseeable horizon (e.g. AWS for compute) and the optionality is unrealistically remote.
- The vendor's API is already neutral (e.g. an industry- standard protocol like S3-compatible object stores).
Composes with¶
- patterns/per-tenant-workspace-in-third-party-saas — pair them: vendor abstraction lets you swap the vendor; the workspace-per-tenant primitive is what gets re-created in the new vendor on swap.
Seen in¶
- sources/2026-05-14-instacart-scaling-personalized-marketing-for-multi-tenant-commerce-platforms — first wiki canonicalization. Instacart's CRM Service explicitly built to "change providers in the future, support multiple providers at once, and avoid tightly coupling our core platform to any one vendor."