"We integrated a CPaaS API" is usually said as though messaging is now done. It is the point at which the actual work starts to accumulate — quietly, on a team that has other priorities.
This is an attempt to describe that work honestly, and then to lay out the three realistic options without pretending one of them is always right.
What exists after the API integration
A stable app-facing contract and provider adapters
Your application should call one internal interface — send a message, receive a status — and never import a provider SDK. Everything provider-specific belongs behind an adapter that translates your request, maps statuses and errors into your vocabulary, absorbs that provider's retry quirks and reports health.
That is a modest amount of code and a permanent amount of maintenance. Providers change response shapes, add status codes, deprecate endpoints and alter throughput rules. Each adapter needs an owner who notices.
Sender registrations and market-specific onboarding
Sender identity is not a field you fill in at send time. Depending on the market it is a registered alphanumeric sender ID, a long number, a short code, or a registered brand and campaign, with rules that differ by market and by traffic category. Registrations have lead times, expiry, renewal, and rejection paths that need someone to interpret and resubmit.
Each new market is a project with an external dependency you do not control. Each new provider in an existing market may need its own registrations rather than inheriting yours.
Canonical status and error mapping, and reconciliation
Provider status vocabularies differ, and storing them raw makes every report provider-specific. So you map to a canonical set you own, keep the raw values for debugging, and alert on unmapped values rather than collapsing them into "failed".
Then there is reconciliation, which teams routinely skip: callbacks get lost, so messages sit in non-final states forever unless a job queries final status past a threshold. The size of that reconciliation gap is itself a monitoring signal — it usually rises before anyone notices a broken endpoint.
Routing, traffic-class isolation, retries, idempotency, failover
Routing is configuration that maps destination, channel and traffic class to a provider, a sender identity and a throughput allowance — changeable without an application release, or it is not really routing.
Around it sits the harder logic: traffic-class queue separation so a marketing batch cannot delay verification traffic; a single owner for retry policy, because otherwise the application, the platform and the provider all retry at once; idempotency and client references so failover does not duplicate messages to real people; treating a request timeout as ambiguous rather than failed; hard delivery deadlines so nothing arrives long after it was useful; and failure detection that is per route, per market and per carrier, because degradation is usually partial rather than total.
Monitoring, on-call, incident response and vendor escalation
This is the part that does not fit a product roadmap. It means route-level alerting rather than a global error rate, canary traffic on live routes because sandboxes cannot reproduce carrier filtering, someone reachable when a market degrades at 02:00, and the ability to raise and pursue an escalation with a provider — which in practice means knowing which contact matters, what evidence they will ask for, and how to keep the ticket moving.
The escalation cost is easy to underestimate. Delivery problems are frequently ambiguous: an application-layer conversion drop with clean-looking delivery receipts, or filtering in one carrier that the provider cannot see from their side. Making progress requires evidence you have to have been collecting already.
Vendor commercial management and invoice reconciliation
Rate cards vary by destination and change. Invoices need to be reconciled against your own message and segment records, which requires storing segment counts at submission time. Add contract renewals, volume commitments, minimum spends, credit terms, and a second provider maintained partly so the first has an alternative. This is a procurement and finance workload, not an engineering one.
Data retention, suppression ownership and change control
Consent evidence, opt-outs and suppression must live in a store you own and that every sending path checks — including one-off exports and ad-hoc tools. Retention periods for message content and destination numbers need a decision and enforcement. Message bodies and numbers should be redacted in logs by default, with an audited path to view them during an investigation.
Then change control: who may change a route, a sender, a template or a throughput limit; how that change is recorded; and how it is reversed. Most messaging incidents that are not provider outages are configuration changes nobody logged.
The three options
1. Direct single-provider integration
Integrate one CPaaS provider, use their sender registrations, their statuses and their support.
Suits: one or two markets; modest volume; messaging supporting the product rather than central to it; a team that would rather spend engineering time elsewhere; early-stage products where the traffic pattern is still unknown.
Accept: provider outages and provider filtering decisions are your outages; commercial terms have limited leverage; provider-specific detail tends to spread through the codebase; and cost to change provider grows over time and is rarely measured until it must be paid.
Honest note: for a large number of platforms this remains the correct choice, and adding a multi-provider layer before there is a real reason is a common and expensive form of premature engineering. The one thing worth doing early is the internal contract, because it is cheap now and expensive later.
2. Build and self-operate a multi-provider layer
Own the abstraction, adapters, routing, registrations, monitoring, on-call and vendor relationships in-house.
Suits: messaging is core to the product or a material cost line; several markets with genuinely different requirements; specific routing or data-residency needs no external layer will match; an existing platform team already carrying 24/7 on-call; or a strategic need to own the capability outright.
Accept: it is a standing team commitment, not a project. The engineering is the smaller half; registrations, escalation, reconciliation and commercial management are the larger half. Second-provider maintenance is ongoing even when it carries little traffic — an untested failover route is not a failover route. And on-call for messaging competes with on-call for your product.
Justified when the volume, margin or strategic importance of messaging makes the dedicated capacity worth its cost, and you can honestly staff the operational half.
3. Managed operations layer
Keep a single app-facing contract and put the adapters, routing, registrations, monitoring, escalation and vendor management with a provider whose job that is.
Suits: multi-market platforms without a messaging team; teams that have already discovered the operational half; organisations that want multi-provider capability without staffing it; and cases where registration and escalation workload, rather than code, is the bottleneck.
Accept: a dependency on an operational partner, integration work to move to the shared contract, and diligence on what you can see and export. The right questions are about visibility and exit: can you get per-route status and outcome data, can you export message history, consent and suppression records, are registrations held so another arrangement can be onboarded in parallel, and can you run traffic through two arrangements at once to compare.
Comparison
| Direct single provider | Build and self-operate | Managed operations layer | |
|---|---|---|---|
| Engineering to start | Lowest | Highest | Moderate (integrate one contract) |
| Ongoing engineering | Low, until you add markets | Continuous | Low |
| Registrations and market onboarding | Provider handles within their scope | You own entirely | Handled with you |
| Multi-provider failover | Not available | Available if you build and test it | Available |
| Route and traffic-class control | Provider-defined | Complete | Configurable, within an agreed model |
| On-call and escalation | Your team, via provider support | Your team, direct with vendors | Operated by the partner |
| Commercial leverage | Limited | Direct with each vendor | Supplied routes, your own contracts, or both |
| Data and suppression ownership | Split with provider | Fully yours | Contractual — check exportability |
| Cost profile | Simple, per-message | Per-message plus dedicated headcount | Per-message plus operations |
| Main risk | Single-provider dependency | Under-staffing the operational half | Partner dependency; verify exit terms |
| Best when | Few markets, messaging is supporting | Messaging is core and staffable | Multi-market without a messaging team |
Where Flowstates sits
Flowstates operates the layer described above, and can supply the routes underneath it. Customers run one of three models:
- Supplied routes. Buy channels from Flowstates and have the gateway, routing, registrations, monitoring and escalation operated as one service.
- BYOV. Keep your existing vendor contracts and commercial relationships, and have Flowstates operate the gateway, routing and escalation layer above them.
- Hybrid. Supplied routes in some markets or traffic classes, your own vendors in others, under one app-facing contract and one operational owner.
What that means concretely: one internal send/status contract for your application, provider adapters maintained outside your codebase, sender registrations and market onboarding run with you, canonical status mapping and per-route outcome data, traffic-class isolation and failover policy, and named operational ownership for escalations.
What it does not mean: Flowstates does not provide legal compliance and does not replace your own advice on consent, retention or market rules — it helps implement and operate the controls those obligations imply. No arrangement can guarantee delivery outcomes, because carriers and destination networks make filtering and delivery decisions nobody upstream controls.
Decision questions
- If your primary provider degraded in your largest market this week, what would you actually do, and who would do it?
- Can you move a market or traffic class to a different provider through configuration, without an application release?
- Is there provider-specific status handling, error handling or an SDK import in your application code today?
- Who owns sender registrations, and what happens when one is rejected or expires?
- What proportion of messages sit in a non-final status, and who watches that number?
- Can you reconcile a provider invoice against your own message and segment records?
- Are you measuring outcomes at the application layer, or only delivery receipts?
- Who is on call for messaging tonight, and what is their escalation path into each vendor?
- If you had to leave your current arrangement in ninety days, what would you be unable to take with you?
If most of these have clear owners and clear answers, self-operating is realistic. If they do not, the question is not whether that work will happen, but who will be doing it.