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.
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.
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.
Scroll the table sideways →
Which Salesforce API to use for which Litify integration job, and what goes wrong with the obvious alternative
The job
What to build it with
Family
Create an intake from a web form
REST, 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 accounting
Bulk 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 system
Bulk 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 changes
Platform 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 together
Composite API, so related records are created in one round trip with a shared transaction boundary.
Composite
Call an external pricing or verification API from Flow
External 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.
Standard 01
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. Standard 02
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. Standard 03
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. Standard 04
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. Standard 05
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. Standard 06
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.
OL★★★★★
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 LeadFast-growing personal injury law firmPersonal Injury
Case Study
Personal Injury Firm — Multi-State
Streamlining case-to-cash operations with Salesforce, AWS and QuickBooks.
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 ManagerMid-size US family law firm · 150 employeesFamily Law
Case Study
Family Law Firm — 150 Employees, US
A 50% efficiency gain from Accounting Seed and Salesforce integration.
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.
01
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.
02
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.
03
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.
04
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.
05
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.
Go Deeper
The rest of our Litify practice
This page covers one service. Each one below goes into the detail a specific team needs — pick the one closest to the question you arrived with.
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.