Standard testing playbooks often fail for B2B SaaS integrations because they don't account for external systems outside your control. To prevent production failures and data loss, teams should adopt a comprehensive testing framework: unit testing, contract testing, E2E testing, and production monitoring.
The integration worked perfectly in staging. You tested the auth flow, confirmed the data sync, and verified the webhook handler. After that, you put the integration into the marketplace, and a customer activated it.
Three days later, the vendor for a third-party API renamed a field. Your integration returned a null where a string was expected. The integration failed. By the time support tickets brought the problem to your attention, your customer had missed 48 hours of data.
This isn't a hypothetical. Teams building integrations in-house see variants of this story constantly – not because they're careless, but because most testing playbooks weren't written for integration code. Standard unit testing rules tell you to test logic in isolation. General-purpose E2E guides encourage you to simulate the full flow. But neither addresses the specific failure modes that appear when your product depends on systems you don't control.
What then do you do? You need a model that tells you exactly where to focus effort at each stage of development, no matter where your team starts.
That model is a four-layer framework:
- Unit tests – Validate your logic in isolation.
- Contract tests – Validate the relationship with every external system.
- End-to-end tests – Prove the full integration runs correctly.
- Production monitoring – Continuously verify health after deployment.
Each layer catches different failures. Together, they help you ensure that everything is working as it should.
Why integration testing is different
Before getting into the layers, here's why integrations fail in ways ordinary testing doesn't catch.
When you build an integration, you're depending on a third-party API that can change its behavior, schema, rate limits, or auth requirements at any time.
Issues that show up when you test integrations:
- Schema drift – A third-party API adds a new required field, renames one, or changes a type. Your code was written against the old schema. The sync breaks. This is the single most common integration incident, and it's almost entirely preventable with the right testing layer.
- Auth edge cases – OAuth tokens expire. Refresh tokens get revoked when users change passwords. Service accounts get removed. Your integration works until the moment it doesn't.
- Sandbox vs production – Many third-party sandboxes don't accurately reflect production. Volume of data is orders of magnitude different. Certain endpoints behave differently. Features available in production are not available in the sandbox. You test against the sandbox, ship something that's never encountered real production behavior, and find out the hard way.
- Webhook delivery assumptions – Webhooks aren't guaranteed to arrive once, in order, or at all. A handler that assumes exactly-once delivery creates duplicates or drops updates under real conditions.
- Eventual consistency – You write a record to a third-party system and immediately read it back. For many APIs, that returns stale data. Tests that assume immediate consistency pass in a clean sandbox and fail intermittently in production.
- Rate limiting in production – Sandbox rate limits are often far more permissive than production. You may never see a 429 until you're live with real customer data volumes. If your retry logic isn't right, it's a real problem.
The goal isn't to eliminate every one of these. That's not something you can do when you're building integrations with systems you don't control. Rather, the goal is to create a testing stack that catches the most common failures before deployment and identifies the rest after deployment fast enough that you find out before your customers do.
The four layers
The bottom layers are fast, cheap, and run constantly. Upper layers are slower and more realistic. The bottom handles 80% of failures. Most integration bugs live in transformation logic, error handling, and retry behavior, all of which are cheap to test in isolation. Upper layers provide the coverage that isolation can't.
| Layer | Whey they run |
|---|---|
| 4: Production monitoring | Always-on; catches production-only failures |
| 3: End-to-end-tests | Before shipping; catches integration flow failures |
| 2: Contract tests | On every PR; catches third-party schema drift |
| 1: Unit tests | On every commit; catches logic errors |
Layer 1 – Unit tests test the logic, not the network
The biggest mistake that many teams make at this layer is trying to hit a live API during a unit test. That makes your CI pipeline slow and dependent on a connection you don't control. The fix is simple: mock the external calls and test only the code you actually own.
What to cover in unit tests
- Data transformation functions – Field mapping, type coercion, null handling, and default values. If you're taking a contact from Salesforce and mapping it to your product, every field mapping gets tested – including what happens when a field is missing, truncated, or arrives as the wrong type.
- Error classification – Does your code correctly distinguish a transient error (rate limit, timeout) from a fatal one (invalid credentials)? These should trigger entirely different outcomes.
- Retry and backoff logic – Test that exponential backoff backs off correctly, and that it doesn't retry forever on fatal errors. On Prismatic, the platform provides automatic retry with configurable attempts and intervals – but your code still needs to send the right error type so the platform knows when to retry versus fail fast.
- Webhook payload parsing – Test that your handler processes known shapes correctly, ignores unexpected extra fields gracefully, and handles things like missing optional fields without choking.
Here's an example in TypeScript:
123456789101112131415161718192021
Tools for unit testing
Vitest orJest for Node/TypeScript. If you're building code-native integrations on Prismatic, the Prism CLI lets you run local tests against your integration logic before you deploy anything.
What unit tests won't catch
Anything the third-party API does that you didn't anticipate. That's what Layer 2 should handle.
Layer 2 – Contract tests validate relationships
Unit tests prove your code works in isolation. Contract tests confirm that your assumptions about external systems remain true.
This is the layer that seems to be frequently skipped – and it's the most common source of production incidents. Third-party APIs often change without warning. A vendor adds a new required field. An ID that was always a string is now returning as an integer in a new API version. A field you rely on is renamed without any doc change. Your unit tests still pass. Your E2E tests may not cover that code path. The failure shows up in production.
Contract testing catches this class of failure before deployment. A contract is a record of the API response shape your code depends on. Contract tests assert that future responses still match – right field names, right types, and required fields present. When a third-party makes a change your code can't handle, the test fails on your next fixture refresh, not in production.
How contract testing works
- Make a real API call to the third-party sandbox and record the response as a fixture.
- Write assertions: this field exists, etc.
- Periodically re-record fixtures from the live sandbox to stay current with production.
- Run contract tests in CI on every pull request.
- You can leverage
prism components:dev:runto pull live credentials from Prismatic for use in a contract test.
You define what your integration needs to consume the external system, not what the external system thinks it provides. If you only use five fields from a 40-field response, test those five. The fact that the other 35 fields exist is immaterial.
Assertions should include the following:
- Required fields are present
- Field types match what your code expects
- Nested objects have the expected shape
- Enum fields only contain values your code handles
What contract testing doesn't catch
It doesn't catch data where the shape is fixed, but the meaning changed: for example, a field that used to mean "created date" now means "last modified date."
Contract testing tools
Pact is probably the most fully-featured contract testing framework. For simpler setups, JSON Schema validation against recorded fixtures works well with minimal overhead.
Final thoughts on contract testing
Version your fixture files with your integration code. When you update a fixture after a third-party API change, the diff in your pull request makes the change visible to reviewers. This helps teams catch breaking changes before they merge. When you deploy via a Prismatic GitHub Actions pipeline, your contract test runs fit right in with your publish and deploy steps.
Layer 3 – End-to-end tests prove the full flow
E2E tests, by definition, cover all the pieces. This is where you confirm the plumbing is connected, not just that each piece looks correct by itself.
Because E2E tests are slow, the goal is not to maximize E2E coverage but to make it efficient. A small set of high-value scenarios, typically the ones that cover your most customer-critical or revenue-adjacent workflows, provides most of the benefit without destabilizing CI. Make sure you are doing at least one green E2E test per integration before enabling it for customers.
What an E2E test covers
- The ideal path – Authenticate, sync data, verify the expected state in your system.
- Auth failure and recovery – Revoke the test token and verify the integration generates a clear error. On Prismatic, verify that credential errors show up correctly in the execution logs.
- Idempotency – Send the same webhook event twice and verify your system doesn't create duplicates.
- Partial failure and rollback – Simulate a failure mid-flow and confirm the system doesn't end up in an inconsistent state.
- The sandbox problem – Third-party sandboxes are imperfect. Many don't support all production endpoints, apply more permissive rate limits, or behave differently in ways that only matter at scale. Create and maintain a living document of known sandbox vs production differences for each integration you support. When a production bug surfaces that your E2E tests didn't catch, add it to the list.
Final thoughts on E2E testing
Maintain a dedicated test account for each third-party sandbox. On Prismatic, you can use the Prism CLI to script deployment and configuration of test instances as part of your pipeline, keeping E2E setup fully automated.
Layer 4 – Production monitoring ensures that testing doesn't stop at deployment
No test environment fully replicates real customer data volumes, timing, or config changes. Layer 4 is what closes that gap, and it's where Prismatic does the heaviest lifting for teams building on the platform.
Credentials expire. API rate limits change. Third-party services degrade. Customers modify configs in unexpected ways. None of these show up in a pre-deployment test suite. But they do show up in support tickets at 3 AM if you don't have production monitoring in place.
What production monitoring includes (Prismatic edition)
- Execution monitoring across all customers – Prismatic tracks every integration execution across your entire customer base – what ran, when, whether it succeeded, how long it took, and which version of the integration was running. You can filter across all customers or drill into a specific instance. This kind of cross-customer visibility is genuinely difficult to build yourself when you're managing integrations for dozens or hundreds of tenants.
- Configurable alerting – Set alerts to fire on execution failures, elevated error log rates, executions that exceed a latency threshold, or instances that haven't run when they should have. Alerts route via email, SMS, or webhooks to Slack, PagerDuty, or any other tool your on-call team uses.
- Log streaming – Prismatic retains step-level execution logs (including timing, step status, and error details) for 14 days. You can stream those logs in real time to Datadog, New Relic, or any other service that accepts
HTTP POST. This means integration logs can live alongside the rest of your observability stack, not in a separate dashboard that nobody opens until a customer calls. - Execution replay – When an integration fails because a third-party API was temporarily unavailable, Prismatic's replay feature lets you re-run the failed execution with the same input payload once the issue is resolved – without data loss, and without asking the customer to re-trigger their action.
- Automatic retries – For transient failures, Prismatic's automatic retry re-attempts failed executions up to 10 times with a configurable interval. You can also configure retry cancellation. If a newer request arrives for the same resource, older queued retries are cancelled so old data doesn't overwrite newer updates.
Final thoughts on production monitoring
For teams using Prismatic, Layer 4 largely comes down to "Configure your alerts intelligently and make sure logs are streaming to your observability platform." The infrastructure is already there; you just need to use it.
Testing webhooks specifically
Webhooks introduce testing challenges that don't cleanly fit into the four-layer structure, so they warrant separate mention. The core problem is that you can't call a webhook to test it; rather, the third party calls you. In local development, your environment usually isn't reachable from the internet.
Testing webhooks in local development
Use a tunneling tool like ngrok or localtunnel. Many third-party platforms that support webhooks also include a "send test event" button. Prismatic's integration designer lets you send test payloads directly to your trigger during development without needing an external tunnel.
Testing webhooks in CI
Save real webhook payloads from sandbox events as fixtures and replay them against your handler. This is faster and more reliable than depending on the third party to fire events on demand.
What every webhook test should include
- HTTP 200 responses are returned before processing – Webhook delivery systems have short timeouts. A slow response can be marked as failed and retried, causing duplicates. Acknowledge receipt immediately, but then let the data process asynchronously. Prismatic's trigger architecture handles this correctly by design.
- Idempotency – That the same payload delivered twice doesn't create duplicate state.
- Invalid signatures are rejected with 401 – Always verify before processing. (See our post on securing webhook endpoints with HMAC.)
- Unknown extra fields in the payload are fine – It's common for APIs to add fields over time. Build your integration to handle them gracefully.
Final thoughts on testing webhooks
If your integration assumes webhook events arrive in sequence, test what happens when contact.updated arrives before contact.created. This should be rare, but it's often catastrophic when it does occur. A single test case can forestall it.
Fitting the layers into your CI/CD pipeline
| When | Tests to run | Trigger |
|---|---|---|
| Every commit | Unit tests | Push |
| Every pull request | Unit + contract tests | PR open/update |
| Merge to main | Unit + contract + E2E (critical paths) | Merge |
| Nightly | Full E2E suite | Scheduled |
| Always-on | Prismatic execution monitoring + alerting | Continuous |
A few rules can help keep this sustainable for the long-term:
- Keep the PR gate efficient – Unit and contract tests should run together in less than 2 minutes. Anything more than that, and you risk the tests being skipped.
- Treat flaky tests as bugs – A test that fails intermittently without a code change is worse than no test. It trains your team to ignore failures. Either fix or delete those tests instead of kicking the can.
- Run E2E tests as advisory on PRs, not a gate – E2E tests against sandboxes are inherently more fragile: the sandbox might be down, rate limits might be hit, or test data might be in an unexpected state. Gate on unit and contract tests.
- Automate E2E setup with the Prism CLI – Rather than manually configuring test instances before each E2E run, script the deployment and configuration using Prism.
Where should you start?
You don't need to implement everything all at once. Here's how you can move into integration testing in stages:
| Stage | What you have | What's needed next |
|---|---|---|
| A: No tests | Manual QA only | Unit tests for transformation logic and error handling |
| B: Unit tests only | Your logic is tested | Contract tests + webhook replay tests |
| C: Unit + contract tests | Schema changes are caught in CI | E2E tests for critical paths and key failure modes |
| D: Full test suite | Pre-deploy confidence | Configure Prismatic alert monitors + log streaming |
| E: Full suite + monitoring | End-to-end confidence | Proactive CS workflows based on integration health data |
Common issues with integration testing
- Over-building in E2E tests – If you mock all external calls in your E2E suite, you're essentially running more unit tests with extra steps. Let contract tests be the source of truth for external behavior but let E2E tests make real sandbox calls.
- Maximizing E2E coverage – More E2E tests mean a slower CI pipeline. Build a small set of critical workflows and keep them up to date and correct, rather than chasing comprehensive E2E coverage.
- Stopping at deployment – In integration-heavy systems, many failures occur days or weeks after deployment. Without production monitoring, these are only visible from customer reports. Layer 4 needs to be in place to catch this failure type.
Discover failures before they cause issues
Integration testing is complex. The four layers help ensure complete testing coverage, each one catching what the others miss:
- Unit tests catch your logic errors on every commit.
- Contract tests catch third-party schema drift on every pull request.
- E2E tests catch integration flow failures before you ship.
- Production monitoring catches failures after deployment, but (often) before your customers do.
If you're currently building integrations in-house and the testing and infrastructure overhead is consuming engineering cycles that should go toward features, learn what typically breaks when in-house integration infrastructure scales and how teams have moved that burden off their plate.
Prismatic's platform includes built-in execution monitoring, configurable alerting, step-level logging, log streaming, automatic retries, and execution replay. It's everything you need to power Layer 4, and you don’t need to build the infrastructure.
Jump into a free trial to see how it works.




