Salesforce · Integration Engineering

Anything integrates at ten records an hour. Build for the Tuesday somebody loads fifty thousand.

Litify runs on Salesforce, so its integration surface is the Salesforce one: REST, Bulk and Composite APIs, Platform Events, External Services, named credentials. The engineering that matters is choosing correctly between them, respecting limits that are shared across your whole org, and building the retry, idempotency and observability that decide whether it survives production. Built bulk-safe from the first commit, not patched after the first failure.

API Surface
WHAT YOU INTEGRATE WITH REST · Bulk · Composite Sync, batch and chained calls Events & CDC Platform Events · Change Data Capture External Services Named Credentials Connect APIs ENGINEERING DECISIONS API Choice Sync or async, row or batch Limit Budget API calls, CPU, SOQL, heap Idempotency Safe to replay, safe to retry LIMITS ARE ORG-WIDE, NOT PER APP 2πr WHAT PRODUCTION NEEDS Recoverable Failure Dead letters and a replay path that works Observability You know it broke before the client does Headroom Survives a migration and a mass billing run
200
Records per batch — the number everything is tested against
4
API families selected between, not defaulted to
12+
Years of Salesforce delivery
40+
Consultants, architects & developers

Trusted by 500+ organizations — including law firms and legal technology companies building their case, billing and reporting operations on Salesforce with Twopir Consulting.

Social Justice Collaborative
Bernstein Liebhard LLP
LegalZoom
Sterling Law Offices, S.C.

Engineering Capability

  • Salesforce Partner
  • REST & Bulk API
  • Platform Events
  • Apex & Async
  • OAuth & Named Credentials
  • Idempotency
  • Governor Limits
  • Observability
Where Custom Builds Break

Six engineering failures we are called in to fix

Every one of these passes a demo. They fail in production, usually at the worst possible moment — during a migration, a mass billing run, or a month-end close.

Row-at-a-time against a Bulk problem

An integration making one REST call per record is fine at fifty records and catastrophic at fifty thousand. It exhausts the org's daily API allocation, which is shared — so it degrades every other integration you own.

No idempotency, so a retry duplicates

The call times out, the client retries, and the record is created twice. Without an external ID or an idempotency key, "safe to retry" is not true, and the cleanup is manual and unpleasant.

Errors swallowed by a catch block

A try/catch that logs nothing and continues. The integration reports success, the data never arrived, and the first anyone knows is a reconciliation weeks later — if anyone runs one.

Credentials in code, or in a custom setting

Hard-coded secrets, or an integration user whose password expires on a schedule nobody tracks. Named credentials and proper OAuth exist precisely to avoid this, and retrofitting them is worse than doing it right.

Synchronous calls inside a trigger

A callout on record save that blocks the user, counts against synchronous limits, and fails the whole transaction when the remote system is slow. Almost always belongs in async, and almost never is.

Hard-coded IDs and label lookups

Record type IDs, Case Type IDs and picklist labels baked into the integration. It works until a sandbox refresh, a rename or a deployment to a different org, and then it fails in a way that is hard to trace.

The Surface You Build On

Litify's API is the Salesforce API

Litify is a managed package, so it does not expose a separate integration gateway — you integrate with Litify by integrating with Salesforce. That gives you the full platform surface: the REST API for record-level work, the Bulk API for volume, the Composite API for chained calls in one round trip, Platform Events and Change Data Capture for event-driven flows, External Services for declarative consumption of outbound APIs, and named credentials for auth.

It also means Litify inherits the platform's constraints. API call allocations, Apex CPU time, SOQL query limits, heap size, callout timeouts and concurrent request caps all apply, and critically they are org-wide rather than per-application. An integration that burns the daily API allocation degrades every other integration in the org, including ones built by someone else years ago.

One practical caution specific to Litify: public sources disagree on the package's namespace and custom API names, and the object and field reference sits behind a customer login. Anything you read online about litify_pm prefixes should be treated as unconfirmed. We query the org directly to establish the real object and field names before writing a line of integration code.

REST API

Record-level create, read, update and delete. The default for low-volume, interactive integration.

Bulk API 2.0

Asynchronous, batched, for volume. What a migration or a nightly sync should be using.

Composite API

Several related calls in one round trip, with a shared transaction boundary where needed.

Platform Events

Publish-subscribe for event-driven integration, decoupling producer from consumer.

Change Data Capture

Streamed record changes without polling, for keeping an external system in step.

External Services

Declarative consumption of an outbound API, callable from Flow without Apex.

Named Credentials

Auth and endpoint configuration outside code, with OAuth token lifecycle handled.

Async Apex

Queueable, Batch and Future for work that must not run in the user's transaction.

Engineering Decisions

Four choices that decide whether it survives production

These get made in the first design session, and they are expensive to reverse. The rest of an integration build is comparatively mechanical.

Decision 01 · Transport

Which API, and synchronous or not

The single most consequential choice. Volume, latency tolerance and transaction semantics decide it, and defaulting to REST because it is familiar is how orgs exhaust their API allocation.

  • REST for interactive, low-volume record work
  • Bulk API 2.0 for anything batch or migratory
  • Composite to collapse chatty call sequences
  • Platform Events where producer and consumer decouple
  • Change Data Capture instead of polling
  • Async Apex for anything that must leave the transaction

Failure mode Row-at-a-time against a bulk problem. It passes every test at demo volume and exhausts a shared, org-wide allocation in production.

Decision 02 · Identity

How records are matched across systems

Determines whether a retry is safe. External IDs with upsert are the mechanism that makes an integration idempotent, and retrofitting them after go-live means reconciling everything already created.

  • External ID fields on both sides
  • Upsert rather than create-then-update
  • Idempotency keys on inbound requests
  • No hard-coded record or record type IDs
  • Case Type resolved by ID, never by name
  • A documented matching rule for near-duplicates

Failure mode A timeout, a retry, and two records where there should be one. Without an external ID, "safe to retry" is simply not true.

Decision 03 · Auth

How the integration proves who it is

Named credentials and OAuth with a dedicated integration user, least-privilege permissions, and a credential lifecycle someone owns. The alternative is a secret in code and an outage when it expires.

  • Named credentials, never secrets in code
  • OAuth client credentials or JWT bearer flow
  • A dedicated integration user, least privilege
  • Permission sets scoped to the objects touched
  • Credential expiry tracked and owned
  • IP restrictions where the endpoint allows

Failure mode A password expiry nobody tracked, on an account a contractor created. Works perfectly for eighteen months, then stops on a Saturday.

Decision 04 · Recovery

What happens when the far side is down

Retry with exponential backoff, a dead-letter store for what cannot be delivered, and a replay path someone can actually run. Designed in from the start, because it cannot be added convincingly later.

  • Retry with exponential backoff and a cap
  • Dead-letter store for undeliverable payloads
  • A replay procedure your team can execute
  • Alerting to a person, not to a log
  • Reconciliation between both systems
  • Circuit breaking when the far side is degraded

Failure mode Silent drift. The integration does not fail loudly — it stops, and the two systems tell different stories until someone notices a number is wrong.

Which Salesforce API to use for which Litify integration job, and what goes wrong with the obvious alternative
The jobWhat to build it withFamily
Create an intake from a web formREST, single record, with an external ID for idempotency and the Case Type resolved by record ID rather than by name.REST
Nightly sync of time entries to accountingBulk API 2.0. Row-at-a-time REST here is what exhausts a shared daily API allocation.Bulk
Migrate years of matters from a legacy systemBulk API 2.0 with staged loads, upsert on external ID, and automation deliberately disabled during the run.Bulk
Notify an external system the moment a stage changesPlatform Events or Change Data Capture. Polling for this wastes calls and adds latency for no benefit.Events
Create a matter plus its roles and documents togetherComposite API, so related records are created in one round trip with a shared transaction boundary.Composite
Call an external pricing or verification API from FlowExternal Services with a named credential, so there is no Apex to maintain for a simple callout.External Svc
What We Engineer

Six engineering workstreams, and the standard we build to

This is what a custom Litify integration engagement actually contains. If a proposal you are comparing does not mention most of it, it is quoting for the happy path only.

Integration Architecture

Transport selection, sequencing, transaction boundaries and failure semantics, decided before anything is written. The design document is short and it prevents most of the expensive mistakes.

  • API family selected per flow, with reasoning
  • Sync versus async boundary defined
  • Transaction and rollback semantics stated
  • Payload contracts and versioning
  • Limit budget allocated per integration
  • Failure semantics agreed with the business

Apex & Async Development

Where configuration cannot reach. Bulkified, test-covered, and written so a Litify release does not break it.

  • Bulkified to 200 records as standard
  • Queueable and Batch for async work
  • No SOQL or DML inside loops, enforced in review
  • Selective queries against indexed fields
  • Test coverage with real bulk assertions
  • Defensive against package object changes

Event-Driven Design

Platform Events and Change Data Capture where decoupling the producer from the consumer is the right answer — which is more often than most law firm orgs assume.

  • Platform Event schema and versioning
  • Change Data Capture instead of polling
  • Replay ID handling and gap recovery
  • Subscriber resilience and ordering
  • Event volume against publishing limits
  • Fallback when a subscriber is offline

Auth & Credential Architecture

Named credentials, a dedicated integration user with least privilege, and a lifecycle somebody owns. Unglamorous and the cause of a large share of production outages.

  • Named credentials, no secrets in code
  • OAuth client credentials or JWT bearer
  • Dedicated integration user, least privilege
  • Permission sets scoped per object
  • Credential expiry tracked with an owner
  • Rotation procedure documented

Limit Engineering

Governor and platform limits treated as a shared budget across the org, because that is what they are. Litify shares them with everything else you run.

  • Daily API allocation budgeted per integration
  • Concurrent request and timeout handling
  • CPU, heap and SOQL limits under bulk
  • Large data volume and skew mitigation
  • Selective query and index strategy
  • Load-tested before production, not after

Observability & Recovery

The difference between an integration that survives a year and one that quietly stopped. Built in the same engagement, never deferred.

  • Structured logging with correlation IDs
  • Alerting to a person, not a log file
  • Dead-letter store and replay procedure
  • Reconciliation between both systems
  • Health endpoint or heartbeat check
  • A runbook your team can operate from
Standards We Build To

Six engineering rules, applied without exception

These are not preferences. Each one exists because its absence has caused a production incident in a Salesforce org, usually more than once.

Bulk-Safe To 200 Records

Every piece of Apex and every integration path is written and tested against a 200-record operation from the outset. Data loads, mass reassignment and integration writes all arrive in bulk eventually.

Enforced by Code review plus test methods that assert on bulk behaviour, not on a single-record happy path.

No SOQL Or DML Inside A Loop

The oldest rule on the platform and still the most common cause of governor limit failures in inherited code. Query once, work in collections, write once.

Enforced by Static review on every change, and bulk test assertions that fail loudly if it regresses.

External IDs And Upsert

Every integrated object carries an external ID, and inbound writes use upsert rather than create. This is what makes a retry safe, and it cannot be retrofitted cheaply after go-live.

Enforced by The integration contract — no inbound flow ships without a documented matching key.

No Hard-Coded IDs

Record type IDs, Case Type IDs and picklist values are resolved at runtime or held in custom metadata. Hard-coded IDs break on sandbox refresh and on deployment to a different org.

Enforced by Custom metadata for configuration, and a review check that rejects literal 15 or 18-character IDs.

Callouts Leave The Transaction

No synchronous callout in a trigger path that a user is waiting on. Queueable or Batch, so a slow remote system cannot block a save or fail the transaction around it.

Enforced by Architecture review — the sync/async boundary is decided in design, not discovered in testing.

Every Failure Reaches A Person

Structured logging with correlation IDs, a dead-letter store, and alerting that reaches a named owner. An error written only to a debug log is an error nobody will ever see.

Enforced by A monitoring runbook delivered with the integration, naming who is alerted and what they do.
How We Deliver

Five phases, and we query your org in the first one

Technical discovery is genuinely technical here. We establish the real object and field names in your org rather than working from documentation that may not match it.

Phase 01

Technical Discovery

We query the org to establish the real namespace, objects and fields, confirm the package version, and measure current API consumption and limit headroom. Public sources on Litify API names are unreliable; the org is not.

Phase 02

Design

Transport selection per flow, payload contracts, identity and matching keys, auth model, limit budget and failure semantics. Short document, reviewed with your technical lead.

Phase 03

Build

Bulkified, test-covered development against the standards above. Built in a sandbox with realistic data volume rather than a handful of test records.

Phase 04

Load & Failure Testing

Tested at volume and tested failing: the far side down, a timeout mid-batch, a duplicate retry. An integration that has only been tested succeeding has not been tested.

Phase 05

Deploy & Operate

Deployment through your release process, monitoring live, a runbook with the replay procedure, and a named owner with credential expiry dates in a calendar.

Why discovery queries the org Litify's object and field reference sits on its Success Community behind a customer login, and public sources disagree on the package namespace — litify_pm is commonly cited but should be treated as unconfirmed until verified. Writing integration code against assumed API names is how a build passes in one sandbox and fails in production. We run the metadata queries in week one and work from what your org actually reports.

When You Need This

Four situations that need engineering, not configuration

Plenty of integration work is configuration. These four are the cases where it genuinely is not, and treating them as if they were is how projects overrun.

High-Volume Data Movement

Migrations, nightly syncs and anything touching thousands of records. Bulk API design, staged loads and limit budgeting are engineering problems with no configuration equivalent.

A System With No Connector

A court system, a medical records provider, a niche practice tool. If it has an API, it can be integrated — the work is in the contract, the identity model and the failure handling.

Event-Driven Requirements

When an external system must react the moment something changes in Litify. Platform Events and Change Data Capture beat polling on latency, cost and API consumption.

An Org Already Near Its Limits

Where existing integrations are consuming the API allocation and adding another risks degrading them all. This needs measurement and budgeting before anything new is built.

Client Outcomes

Legal platforms we have actually built

Two engagements from our legal practice, both built on integration between case management, document processing and financial systems under real transaction volume.

★★★★★
Twopir provided Salesforce customisation and integration services to help us build a robust, compliant, and scalable legal operations platform — connecting case management, document processing, and financial systems into one unified workflow. The result was transformative for how we run case-to-cash operations.
Operations Lead Fast-growing personal injury law firm Personal Injury
Case Study

Personal Injury Firm — Multi-State

Streamlining case-to-cash operations with Salesforce, AWS and QuickBooks.

40%+ Faster case-to-settlement processing
45% Reduction in reconciliation effort
35% Improvement in data accuracy
Read Full Case Study
★★★★★
Twopir's specialized Salesforce customization enabled efficient integration of third-party systems and streamlined administration and billing, leading to seamless financial operations and enhanced productivity. Automated mass billing and matter management minimized errors across our entire legal workflow.
Practice Manager Mid-size US family law firm · 150 employees Family Law
Case Study

Family Law Firm — 150 Employees, US

A 50% efficiency gain from Accounting Seed and Salesforce integration.

50% Increase in operational efficiency
45% Productivity gains from automation
35% Faster lead qualification & conversion
Read Integration Story
Why Twopir

Integration engineering that assumes production

The gap between an integration that demos and one that runs is entirely in the parts nobody asks to see. We build those parts first.

We query your org before we design anything

Public sources on Litify's namespace and API names disagree with each other, and the authoritative reference needs a customer login. We establish the real object and field names in week one rather than writing code against an assumption.

Bulk-safe from the first commit

Everything written and tested against 200 records from the outset. Retrofitting bulk safety after a limit failure in production means rewriting the parts that were hardest to get right.

We test it failing, not just succeeding

The far side down, a timeout mid-batch, a duplicate retry, a malformed payload. An integration that has only been tested on the happy path has not been tested at all.

We treat limits as an org-wide budget

API allocation, CPU and concurrent requests are shared across everything in your Salesforce org. We measure current consumption before adding to it, because one greedy integration degrades systems it has nothing to do with.

We extend around the package, never into it

Custom objects, Apex, Flow and Lightning Web Components built so the vendor's next release upgrades cleanly. A firm that cannot take a Litify upgrade has bought a fork, not a platform.

Common Questions

Answers before the first call

Not a separate one. Litify is a managed package on Salesforce, so you integrate with it through the Salesforce API surface — the REST API for record-level work, Bulk API 2.0 for volume, the Composite API for chained calls, Platform Events and Change Data Capture for event-driven flows, External Services for declarative outbound calls, and named credentials for authentication. That is an advantage: it is a mature, well-documented, widely-supported surface rather than a proprietary gateway with its own quirks and its own rate limits.

It depends on volume, latency tolerance and transaction semantics. REST for interactive, low-volume record work such as creating an intake from a web form. Bulk API 2.0 for anything batch or migratory — a nightly accounting sync or a legacy migration — because row-at-a-time REST at that volume exhausts a daily API allocation that is shared across your whole org. Composite where several related records must be created in one round trip. Platform Events or Change Data Capture when an external system needs to react to a change, which beats polling on latency, cost and API consumption.

The ones that actually bite are the daily API call allocation, Apex CPU time, SOQL query limits, heap size, callout timeouts and concurrent request caps. The critical point is that these are org-wide, not per-application: Litify shares them with Sales Cloud, Service Cloud, every other package and every existing integration. An integration designed without a limit budget can degrade systems it has nothing to do with, and that class of failure is genuinely hard to diagnose. We measure current consumption and headroom during discovery before adding anything new.

External IDs and upsert. Every integrated object carries an external ID field holding the far system's key, and inbound writes upsert on it rather than creating. That way a timeout followed by a client retry updates the existing record instead of producing a duplicate. Inbound requests also carry an idempotency key where the protocol allows. This has to be designed in from the start — retrofitting external IDs after go-live means reconciling everything already created, which is slow, manual and error-prone.

Integrations built against the Salesforce API surface are generally safe, because they use platform APIs rather than package internals. The risk sits in code that references Litify objects and fields directly, which is why we write defensively, resolve configuration from custom metadata rather than hard-coding it, and never bake in record type or Case Type IDs. We also verify against a Litify release in a sandbox before it reaches production as part of ongoing support, so an upgrade is a routine check rather than an incident.

Three things, all built in the same engagement rather than deferred. Structured logging with correlation IDs so a single transaction can be traced end to end. Alerting that reaches a named person rather than a debug log nobody reads. And a reconciliation process comparing both systems at a cadence suited to the data, so drift is caught deliberately rather than noticed accidentally. Plus a dead-letter store and a replay procedure your own team can execute. If an integration cannot tell you it is healthy, it is not finished.

That page is about which systems should connect and what the business consequence is — master data ownership, direction of flow, what the firm gets, which integration to do first. This page is the engineering underneath: API selection, governor and platform limits, auth architecture, idempotency, bulk behaviour and observability. If you are deciding whether to connect your accounting system, start there. If you are scoping a custom build and need to know how it behaves under a fifty-thousand-record load, you are in the right place.

Next Step

Bring us the API docs and the volume, we will tell you what it really takes

A technical scoping conversation covers the systems involved, realistic data volumes, your org's current limit headroom, and which API family each flow should use. Bring your developer — this one goes deep quickly.

API selection · limit budget · idempotency · retry and replay · observability