Design integration boundaries around carrier capabilities instead of assuming every provider supports the same operations, protocols, and recovery guarantees.
Every Carrier Surface Has Different Capabilities
Some carriers expose idempotent write keys, some require SOAP headers for auth, some push tracking webhooks, and some still force polling or batch manifests. A capability matrix makes those differences explicit so your architecture reflects the real contract instead of a happy-path abstraction.
Normalize the Workflow, Not the Raw API Shape
The right adapter boundary preserves one internal model for capabilities like create shipment, void label, fetch tracking, auth refresh, and evidence logging while still respecting protocol-specific details underneath. When teams normalize raw payloads too early, they either hide critical edge cases or leak carrier quirks everywhere else in the codebase.
Carrier Reality
One carrier might support async webhook delivery and native idempotency while another only offers SOAP polling plus manual deduplication. If your internal architecture assumes both are equivalent writes, production failures become much harder to classify and recover.
Capability Gaps Should Influence Runbooks and Roadmaps
A capability matrix is not a one-time design artifact. It should inform onboarding checklists, rollout plans, support expectations, and the sequence in which you add premium or enterprise features later. The carriers with the weakest guarantees deserve the strongest operational guardrails in your architecture.