Salesforce · Slack API & Development

When configuration runs out, the code has to be worth owning.

A custom Slack app is the right answer to a narrow set of requirements and the wrong answer to most of the rest. When it is right, the questions that decide whether it survives are unglamorous: which runtime, how it authenticates, what happens on a rate limit, and who owns it in two years. Apex SDK for Slack or Bolt — chosen deliberately, tested, and handed over.

Runtime Choice
WHAT NEEDS CODE Custom Surfaces Modals · Commands · Shortcuts Event Handling Slack events → Salesforce logic No Connector Exists Bulk Volume Non-Standard Auth TWOPIR BUILD LAYER Runtime In the org, or outside it Credentials Named & External Never a secret in code Resilience Retries · Backoff Dead letters TESTED · VERSIONED · OWNED BY SOMEONE NAMED 2πr WHERE IT RUNS Apex SDK Inside Salesforce, in user context Bolt App Outside the org, own scaling Either Way Documented and handed over CHOOSE · BUILD · TEST · HAND OVER
12+
Years Salesforce & HubSpot Delivery
500+
Clients Served
250+
Deployments Delivered
15+
Certified Partnerships

Trusted by 500+ organizations — including technical teams who needed the part configuration could not reach, and nothing more.

LegalZoom
Magnus Health
Aventria
Sterling Law Offices, S.C.
Ideal Health Consulting

What We Build With

  • Salesforce Partner
  • Apex SDK for Slack
  • Slack API
  • Bolt
  • Platform Events
  • Queueable Apex
  • Named Credentials
  • Custom Workflow Steps
How Custom Builds Fail

The failure modes that only appear in production

None of these show up in a prototype. All of them show up on the day the volume, the token or the person who wrote it goes away.

Built as code when config would do

The requirement sounded technical, so it went to a developer. Six weeks later it is a maintained application doing something a Flow action and a channel policy would have done — and now it needs a release process forever.

No handling for rate limits

The app works until it sends enough to be throttled, then starts dropping messages. Without backoff and a retry path, the only symptom is that some notifications stopped, which nobody notices until somebody asks about a deal.

Secrets in the code

A token pasted into an Apex class or a config file, visible to anyone with read access and impossible to rotate without a deployment. It works, right up until it is the finding in a security review.

No tests on the integration path

Unit tests cover the business logic and stub out the callout, so the part that actually breaks in production — the payload shape, the error response, the retry — is the part with no coverage.

One person understood it

The app is competent and undocumented. When its author leaves, the team's options are to reverse engineer it or to freeze it, and freezing usually wins until it breaks.

Acting as an integration user

Everything runs as a single service account, so every action in Slack is performed by a user with broad access rather than by the person who requested it. The audit trail says the integration did it, which is not an answer.

The Short Version

What building a Slack app actually commits you to

A custom Salesforce–Slack integration is an application: it has a runtime, an authentication model, a deployment process, tests, and someone responsible for it. That is the real cost, and it is why the first question on any engagement here is whether the requirement genuinely needs code at all.

What the platforms provide. Salesforce offers the Apex SDK for Slack, which lets developers build Slack apps that interact with Salesforce data from inside Slack through events, shortcuts and slash commands, and to call Slack API methods from Apex classes in the Slack namespace — documented by Salesforce Developers, where it has been published as a Beta, so its status and surface should be checked against the current release. Slack offers its own API and the Bolt frameworks for apps that run outside the org. Named and External Credentials handle authentication from Salesforce without secrets in code.

What Twopir does. We test whether the requirement really needs code, choose the runtime on the trade-offs rather than on familiarity, keep credentials out of source, design for rate limits and retries before the first send, write tests that cover the integration path rather than stubbing it, and hand over documentation naming an owner.

What the client gets. An application their own team can run, or an honest statement of what it will take to run it. We work with growing, mid-market, and enterprise organizations that need help with complex CRM implementations, integrations, and business system challenges.

The Runtimes

Four places the code can live — and what each costs

The runtime decision is usually made by whoever is available rather than by the trade-offs. It is the choice hardest to reverse later, so it is the one worth spending an hour on.

Comparison of runtimes for a custom Salesforce and Slack application, by where the code runs, how it authenticates and acts, what it suits, and the constraint that decides against it.
RuntimeWhere the code runsActs asBest forThe constraint
Apex SDK for SlackInside the Salesforce org, in Apex.The mapped Salesforce user, in their own context and access rights.Slack surfaces that are mostly about Salesforce data, where staying inside the platform's security model is the point.Salesforce governor limits apply, and it has been published as a Beta — check its status for your release.
Bolt app (outside the org)On your own infrastructure or a serverless platform.Whatever identity you configure — which is a decision, not a default.Heavy processing, non-Salesforce dependencies, or logic that must not consume org limits.You own the hosting, the scaling, the monitoring and the on-call.
Apex callout to the Slack APIInside the org, as a direct HTTP call from Apex.An integration identity held in a Named Credential.Narrow, outbound-only jobs where a full app would be overkill.Outbound only. No interactive surfaces, and easy to scatter across a codebase.
Custom Workflow Builder stepWherever you host the step's logic.The step's configured identity.Giving no-code builders access to an internal system, once.Built once by a developer, then owned as a shared dependency.

Runtimes verified against current Salesforce and Slack developer documentation

Credentials, not secrets

Authentication through Named and External Credentials so tokens are never in source, can be rotated without a deployment, and are not visible to everyone with read access to the org. This is the finding that appears in almost every security review of an inherited integration.

Rate limits, backoff and retries

Slack API methods are rate limited. An app without backoff does not fail loudly, it drops messages quietly — so retry with exponential backoff, a dead-letter path and an alert on repeated failure are part of the first build, not a later hardening pass.

Bulk-safe by construction

Never send a message per record from a trigger. Queue through Platform Events or Queueable Apex and process in controlled batches, because the volume that breaks an integration always arrives after go-live.

Acting as the user, not the service

Where the platform allows it, actions run in the requesting user's Salesforce context so sharing rules and field-level security still apply and the audit trail names a person. An integration user doing everything is convenient and answers no audit question.

What We Build

The development work inside an engagement

Six workstreams. The first exists to make the other five smaller, and frequently ends the engagement early.

Build-versus-configure assessment

Every requirement tested against the declarative options first. We have ended engagements at this step, and we would rather do that than hand you an application you did not need.

Custom Slack apps

Modals, slash commands, shortcuts and event handlers built with the Apex SDK for Slack where the work is Salesforce-centric, or as a Bolt app where it is not.

Custom Workflow Builder steps

Steps for internal systems with no connector, so your ops team can keep building no-code workflows on top without coming back to a developer each time.

Authentication and credentials

Named and External Credentials, scope selection that requests only what the app needs, and a rotation path that does not require a release.

Delivery and resilience

Queued sending, retry with backoff, dead-letter capture and alerting on repeated failure — the difference between an integration that degrades visibly and one that stops silently.

Tests, documentation and handover

Coverage on the integration path rather than around it, plus documentation naming an owner. Code only we understand is a dependency we are not willing to leave behind.

How We Work

From requirement to something you own

Four phases. The first is short, and it is the one that decides whether the other three should happen at all.

Phase 01

Prove it needs code

The requirement tested against object configuration, Flow, Workflow Builder and connector steps before anything is designed. If one of them reaches it, we say so and stop — that is a good outcome, not a lost project.

Phase 02

Choose the runtime deliberately

Apex SDK inside the org, Bolt outside it, a narrow callout, or a custom step — decided on limits, identity model, hosting appetite and who will maintain it, and written down with the reasoning.

Phase 03

Build with the failure paths first

Authentication through credentials, rate-limit handling, retries and dead letters built alongside the happy path rather than after it. Tests cover the integration boundary, not just the logic behind it.

Phase 04

Hand over so it can be maintained

Documentation, a named owner, and a walkthrough with whoever will hold it. Where you have no in-house developer, we say plainly that this is a supported component and what that implies.

Proof

Custom work inside delivered engagements

Delivered Slack engagements on Salesforce. The figures are the ones published on each case study, with their original scope intact.

★★★★★
The goal was never to replace Salesforce — it’s still the system of record. We just made sure the team never had to leave Slack to know what was happening in their pipeline.
Twopir Project Lead SaaS technology client · 2025 Slack Sales Elevate
Case Study

Slack Sales Elevate · Salesforce Integration

Five systems connected into one workflow, including custom integration work alongside the standard Salesforce for Slack apps and Slack Sales Elevate.

5 Systems connected into one workflow
5 Specialist roles on the delivery team
6 Rollout problems found and fixed
Read the Case Study
Case Study

Slack Workspace · 75+ Field Crews

A Slack workspace connected to dispatch, ticketing and CRM so assignments, incident notifications and per-account channels were provisioned rather than created by hand.

75+ Field and office staff onboarded
5,000+ Businesses served by the client
Read the Case Study
Delivery Team

A developer is one of five roles

On a Salesforce–Slack engagement the delivery team is a Salesforce admin, a Slack admin, a developer, a workflow builder and QA. Most of the work is not code, which is exactly why the code that does get written should be the part that needed to be.

5 Specialist roles on delivery
See the Engagement
Why Twopir

We write as little code as the job allows

Every line we write is a line you own. The useful engineering decision is usually the one that avoids writing it.

We try to talk you out of it first

Every requirement is tested against the declarative options before anything is designed. We have ended engagements at that step, and that is the correct outcome when configuration reaches it.

We choose the runtime on trade-offs

Inside the org or outside it is a decision about limits, identity, hosting and maintenance — not about which language the available developer prefers. We write the reasoning down.

We build the failure paths first

Rate limits, retries, backoff and dead letters exist from the first commit. An integration that drops messages silently is worse than one that never worked, because nobody investigates it.

We keep secrets out of source

Named and External Credentials, minimal scopes, and a rotation path that does not need a release. This is the single most common finding when we inherit somebody else's integration.

We are Salesforce architects who write Apex

Governor limits, bulkification, sharing and field-level security are not afterthoughts for us. Acting in the user's context rather than as a service account is a default, not an upgrade.

Common Questions

Answers before the first call

When you need an interactive surface of your own — a modal that collects structured input, a slash command, a shortcut — or when you need to reach a system that has no connector step, or when volume requires delivery patterns the declarative tools do not offer. Outside those cases, configuration usually reaches the requirement, and we will tell you when it does before you commit to owning an application.

It is Salesforce's toolkit for building Slack apps on the Salesforce platform: it lets developers handle Slack events, shortcuts and slash commands, and call Slack API methods from Apex classes in the Slack namespace. Its main attraction is that the app runs inside the org, so actions can happen in the acting user's Salesforce context rather than as a service account. Salesforce has published it as a Beta, so we check its current status and surface against your release rather than assuming.

On four things: whether Salesforce governor limits are a help or a hindrance for your workload, whether actions should run as the requesting user or as a service identity, whether you want to own hosting and on-call, and who will maintain it. Salesforce-centric surfaces usually belong in the org; heavy processing or non-Salesforce dependencies usually belong outside it. We write the reasoning down so the decision can be revisited later on its merits.

By assuming they will be hit. Retry with exponential backoff, a dead-letter path for what still fails, and an alert to a named owner on repeated failure. The dangerous property of a rate-limited integration is not that it fails, it is that it fails quietly — so the alerting matters as much as the retry.

Not in code and not in a config file in source control. Salesforce provides Named and External Credentials for exactly this, which keeps the secret out of the codebase, lets it be rotated without a deployment, and limits who can see it. A token pasted into an Apex class is the most common finding when we audit an inherited integration.

Where the platform supports it, yes, and it is the better default. Actions taken through the Salesforce Slack apps run in Salesforce in the mapped user's context and follow their access rights, so sharing rules and field-level security still apply and the audit trail names a person. An integration user performing every action is simpler to build and answers no audit question.

Possibly not, and that is worth deciding before the build rather than after. Code needs an owner, a release process and someone to call when it breaks. If you have none of those, either the requirement should be met declaratively, or the component needs to sit under a support arrangement — and we will say which of those we think applies rather than leaving you with something unmaintainable.

Next Step

Send us the requirement, we will tell you if it needs code

A technical review covers what you are trying to build, whether the declarative options reach it, and if not, which runtime fits and what owning it will involve. You leave with a recommendation either way — including the one where you do not build anything.

Salesforce architects who write Apex and prefer not to