Salesforce · Communications Cloud

Every line of custom code is a subscription. We help you buy fewer.

Communications Cloud customization is the work that begins where the product's own configuration surface runs out — OmniStudio journeys and agent consoles, integration procedures and data mappers, and Apex where declarative rules genuinely cannot reach. Twopir Consulting builds those extensions, and argues hard about which ones you need. The boundary is written down, and every crossing has a named reason.

Extension Architecture
STANDARD PRODUCT SURFACE Catalog & Rules EPC · Pricing · Eligibility CPQ & Orders Cart · MACD · Orchestration Contracts · CLM Digital Commerce Standard data model TWOPIR EXTENSION LAYER Journeys OmniScript FlexCards Data & Logic Integration Procedures · Mappers Bounded Code Apex behind a stated boundary CONFIGURE FIRST · EXTEND ONLY WITH A NAMED REASON 2πr UPGRADE-SAFE PLATFORM A Small Surface Less to regress at each release It Survives Releases Extensions tested, not rediscovered A Written Boundary Anyone can see why code exists CONFIGURE · EXTEND · DOCUMENT · REGRESS · OWN
12+
Years of delivery
500+
Clients served
40+
Consultants & architects
250+
Deployments delivered

Trusted by 500+ organizations — including connectivity and communications providers extending Salesforce safely with Twopir Consulting.

Kacific
Mitratech
Client A
Client R
Client
Ultra's

Where We Extend

  • Salesforce Partner
  • OmniScript
  • FlexCards
  • Integration Procedures
  • Data Mappers
  • Apex Extensions
  • Lightning Web Components
  • Upgrade Safety Reviews
How Customization Goes Bad

Custom code rarely arrives by decision. It accumulates.

Nobody sets out to build an unsupportable platform. These are the six routes by which operators arrive at one anyway.

Code was written because it was quicker that afternoon

A declarative route existed but took longer to work out than writing the class. Multiply by two years of delivery pressure and the custom surface becomes the platform, with no single decision anyone can point to.

The catalog was not modelled, so logic went into code

Rules that belong in the product model as eligibility and compatibility get expressed in Apex instead. Product managers then cannot change offers without a developer, which is the exact capability the platform was bought for.

Every platform release becomes a project

Extensions were built against internals rather than supported extension points, so each Salesforce release needs an investigation phase. The upgrade cost was real from the start; it just was not visible until the first release.

Nobody can say why a customization exists

The person who knew the reason has left, the ticket is closed, and the code has no stated boundary. It cannot be removed safely, so it is carried forward indefinitely and regressed at every release.

The same journey exists three times

Assisted, self-serve and partner channels each got their own bespoke build. A change to eligibility logic now means three changes, three tests and three chances for them to diverge.

Customization hides a requirement nobody challenged

A significant extension exists to support a process that was never questioned. The cheapest customization is always the one a five-minute conversation with the business removes entirely.

What Customization Means Here

Three surfaces, three different costs

Communications Cloud can be changed on three surfaces, and calling all of them "customization" is how programmes lose control of their upgrade cost. The first is configuration: modelling offers, prices, eligibility and compatibility in the Enterprise Product Catalog, and setting up cart, contract and orchestration behaviour. No code, changeable by trained business users, and essentially free at upgrade time. The second is low-code extension with OmniStudio: OmniScripts for guided multi-step journeys, FlexCards for data and action surfaces, Integration Procedures for server-side orchestration of data, and data mappers for reading, transforming and writing Salesforce data. These are supported extension points, so they carry a real but modest ongoing cost.

The third is custom code: Apex and Lightning Web Components. It is sometimes genuinely necessary — logic that must run mid-transaction, an integration shape no standard interface covers, a computation the declarative surface cannot express. It is also the most expensive thing on the page, because its cost is not the build. It is the regression testing at every platform release, the onboarding of every future developer, and the constraint it places on every later change.

Twopir Consulting's rule is simple and we apply it to our own work: if the product can express it, we configure it. Where it genuinely cannot, we extend on supported points, keep the extension behind a documented boundary, and record why it exists — so that a future team can evaluate whether it still needs to. We will also tell you when a customization you have asked for is solving a process problem that would be cheaper to solve directly.

If the platform is not built yet, the boundary conversation belongs in design — see Communications Cloud implementation. If you have inherited a heavily customized org and want to know what it is costing you, that is an optimization engagement. This page is about building extensions well.

The Boundary

What belongs in configuration, and what earns code

The same table appears in summary on the pillar page. Here it carries the column that actually decides the argument: what the choice costs you every release, forever.

Configuration, low-code extension and custom code — with the ongoing cost attached

What you want to changeRight surfaceOngoing cost
A new bundle, plan or promotionConfiguration — catalog change in EPCNone. This is what the catalog is for
Eligibility, compatibility or discount rulesConfiguration — declarative rules on the product modelNone, provided the rules stay in the model rather than in code
A guided journey for an agent or customerLow-code — OmniScript and FlexCardsModest. Supported extension points, but still regressed each release
Reading, shaping or writing data for a journeyLow-code — Integration Procedures and data mappersModest, and far lower than the equivalent Apex
An integration no standard interface coversCode — a bounded adapter, isolated from the restReal. Owned, versioned and tested like any other interface
Logic that must run mid-transactionCode — Apex behind a documented boundaryHighest. Regression at every release, plus onboarding for every future developer
A process that is awkward in the productUsually neither — challenge the process firstThe cheapest extension is the one a conversation removes

We put this table in front of clients during design, not after. The third column is the part that changes decisions: the build cost of a customization is paid once and is usually small, while the ongoing cost is paid at every release for as long as the platform lives.

What We Build

The extension work, and where each piece is right

Each of these is a supported extension point. We use them in roughly this order of preference, and we say so in the design document.

OmniScript Journeys

Guided, multi-step processes for the flows the standard UI does not serve well — complex B2B ordering, structured troubleshooting, bulk change capture.

  • Journey design with the people who will use it
  • Step, branch and validation logic
  • Reuse across assisted and self-serve channels
  • Save, resume and partial-completion handling
  • Accessibility and keyboard-path testing

FlexCards & Consoles

The data and action surfaces an agent works from: subscriber context, asset state, order status and the next action, on one screen.

  • Subscriber and asset context cards
  • Order and orchestration status surfacing
  • Action wiring back into catalog and order flows
  • Console layout for real handling times
  • Performance tuning on data-heavy cards

Integration Procedures & Data Mappers

Server-side composition: gathering, transforming and sending data between Salesforce and external systems without putting that logic in Apex.

  • Procedure design and chaining
  • Read, transform and write mappings
  • External callout composition and error shaping
  • Caching and response-size management
  • Replacing existing Apex where a procedure will do

Bounded Apex & Components

Where declarative and low-code genuinely cannot reach. Kept small, isolated and documented, with the reason recorded next to the code.

  • Mid-transaction logic the platform cannot express
  • Custom adapters for non-standard interfaces
  • Lightning Web Components for bespoke surfaces
  • Test coverage written as specification
  • A stated boundary, reviewed at each release

Upgrade Safety Review

An assessment of what you have already built, what it will cost at the next platform release, and what can safely be removed or moved back to configuration.

  • Inventory of every extension and its purpose
  • Dependency on internals versus supported points
  • Regression exposure per platform release
  • Candidates for retirement or downgrade
  • A prioritised remediation plan with effort

Enablement & Handover

Making your own team capable on the low-code surface, so the next change does not need us.

  • OmniStudio enablement for internal developers
  • Design patterns and naming standards
  • Code and configuration review practice
  • Documentation your team will actually keep
  • A defined escalation path for the hard cases
How We Work

Five steps, and a challenge at the start of each

The most valuable thing we do on a customization engagement is sometimes to end it early.

Step 01

Challenge the Requirement

Before designing anything we ask what business outcome the customization serves and whether the process itself is the problem. A meaningful share of requested extensions do not survive this conversation, which is the cheapest possible outcome.

Step 02

Find the Lowest Surface

We work down the boundary table from configuration to low-code to code, and we document which surface we landed on and why. If the answer is code, the reason is written down before anything is built.

Step 03

Design the Boundary

Extensions are isolated behind a defined interface, so what is custom is visible and separable. A future team should be able to see the edge of the custom surface without reading everything inside it.

Step 04

Build with Regression in Mind

Tests are written as specification rather than as coverage. When a platform release changes behaviour, the suite tells you what broke and why, instead of leaving it to be discovered by a user.

Step 05

Document and Hand Over

Every extension carries its reason, its owner and its removal criteria. The last one matters most: it is what lets a future team retire a customization instead of carrying it forever out of caution.

What You Get

What disciplined extension actually buys you

Mostly, it buys you optionality — the ability to change your mind later without paying for it twice.

Release

Platform upgrades stop being projects

A small custom surface built on supported extension points means each Salesforce release is a regression run rather than an investigation with an unknown end date.

Ownership

Product changes stop needing developers

Rules that belong in the catalog live in the catalog, so product managers change offers directly — which is the capability the platform was bought to provide.

Clarity

Every customization has a stated reason

Extensions carry their purpose, owner and removal criteria, so a future team can evaluate them instead of carrying them forward out of caution.

Consistency

One journey, not one per channel

Shared OmniStudio components mean a change to eligibility or flow happens once, and assisted, self-serve and partner channels cannot quietly diverge.

Cost

The ongoing bill is visible up front

Because the boundary table puts release cost next to build cost, customization decisions get made with the full price in view rather than only the quote.

Reversibility

Extensions can be removed

An isolated, documented extension with removal criteria can be retired when the product catches up — which it regularly does, and which nobody notices without the documentation.

Why Twopir

We argue against the work we would be paid to do

A consultancy paid by the day has an obvious incentive to build. The boundary table exists partly to hold us to the opposite, in writing, in front of the client.

We challenge the requirement first

Every customization engagement starts by asking what outcome it serves and whether the process is the real problem. A meaningful share do not survive that conversation, and that is the best result available.

We show the ongoing cost, not just the quote

Build cost is paid once and is usually small. Release cost is paid forever. Putting both in front of you at design time is what makes the decision an informed one.

We prefer the lowest surface that works

Configuration, then low-code, then code — and the surface we landed on gets documented with the reason. Nobody has to reverse-engineer the decision later.

We write removal criteria

Every extension records what would make it unnecessary. The platform catches up more often than people expect, and without that note the customization is carried forever out of caution.

We build your team's capability deliberately

Enablement on the low-code surface is part of the engagement, not an upsell. The measure of success is that the next change does not need us.

Common Questions

Answers before the first call

Configuration is changing the product's own model: offers, prices, eligibility and compatibility rules in the Enterprise Product Catalog, and cart, contract and orchestration behaviour. It needs no code, trained business users can do it, and it costs essentially nothing at upgrade time. Customization means building something the product does not express — either on low-code extension points such as OmniScript, FlexCards, Integration Procedures and data mappers, or in Apex and Lightning Web Components. The distinction matters because the cost profile is completely different: configuration is paid once, while custom code is paid again at every platform release, in regression testing and in onboarding for every future developer.

OmniStudio is the low-code toolset used across Salesforce Industries products. It has four main parts: OmniScripts, which are guided multi-step processes; FlexCards, which display data and offer actions; Integration Procedures, which compose and orchestrate data server-side; and data mappers, which read, transform and write Salesforce data. The usual flow is a FlexCard or OmniScript calling an Integration Procedure, which calls a data mapper or an external system. Use it when the standard interface genuinely does not serve a flow well — complex B2B ordering, structured troubleshooting, agent consoles. Do not use it to rebuild something configuration already does, which is a common and expensive mistake.

Not inherently, but it determines how much each upgrade costs. Extensions built on supported extension points are regressed at each platform release, which is real work but bounded and predictable. Extensions built against platform internals, or that duplicate behaviour the product also implements, are where upgrades turn into investigations with an unknown end date. That difference is a design choice made at build time, which is why we document which surface each extension uses and keep custom code behind a stated boundary. Our upgrade safety review exists specifically to measure this on orgs that were built without that discipline.

With an inventory, not a rewrite. We catalogue every extension, what it does, why it was built where that can still be established, whether it depends on supported extension points or on internals, and what it costs at each platform release. That produces three groups: extensions that are fine, extensions that should move back to configuration because the product now expresses them, and extensions that should be removed because the requirement behind them no longer exists. Most orgs have meaningful volume in the second and third groups. The plan that follows is prioritised by release cost, so the most expensive items go first.

That is the intended outcome and we build toward it. Low-code extensions on OmniStudio are designed to be maintainable by a trained internal team, and enablement is part of the engagement rather than an upsell — design patterns, naming standards, review practice and documentation your team will actually keep. Apex extensions need a developer, which is one of the reasons we keep that surface as small as possible. We also define an escalation path for the genuinely hard cases, because pretending every problem is in-house-solvable helps nobody.

Three tests, in order. First, does the business process actually require this, or is the process itself the problem — a meaningful share of requests stop here. Second, can configuration express it, which covers far more than people expect once the catalog is properly modelled. Third, can a supported low-code extension point express it. Only when all three fail do we write code, and when we do, the reason is documented next to it along with the criteria that would make it removable. Typical legitimate cases are logic that must run mid-transaction, an integration shape no standard interface covers, and computations the declarative surface genuinely cannot perform.

Yes, and it cuts both ways. Agentforce actions are grounded in the data and processes the platform exposes, so rules that live in a well-modelled catalog are readable and usable by an agent, while the same rules buried in Apex often are not. Heavy undocumented customization tends to reduce what an AI agent can safely do, because the real behaviour is no longer described by the model. Keeping logic on the configuration and low-code surfaces is therefore an AI-readiness decision as much as a maintainability one — which is covered further on our Communications Cloud AI and Agentforce page.

Next Step

Send us the extension inventory. We will tell you what to delete.

A customization review looks at what has been built, which surface each piece sits on, and what it is costing you at every release. You get a prioritised list of what to keep, what to move back to configuration, and what to retire.

Speak with a team that writes down why the code exists