How to Create a Migration Playbook from Make.com to Native SaaS Integrations
A complete migration playbook for switching unified API providers or iPaaS - with audit checklists, parallel-run patterns, category cutover steps, rollback plans, and timelines.
Your enterprise prospect just finished a great software evaluation. They love your product's core functionality. The UI is exactly what their team needs. Then they ask the inevitable question: "How does this connect to our Salesforce instance?"
You point them to a Make.com scenario template or a Zapier link. The deal stalls. The internal champion ghosts you. Six weeks later, procurement picks the competitor with native Salesforce sync built directly into their settings page.
If your B2B SaaS product is still pointing enterprise customers at a visual workflow builder to handle CRM, HRIS, or ERP syncs, you have a finite runway before that architectural decision starts costing real ARR. Early-stage SaaS teams often use Make.com or Zapier to prototype integrations quickly. These are exceptional platforms for internal operations and citizen developers. But as your product moves upmarket, relying on visual workflow builders for multi-tenant data sync becomes a severe architectural liability.
This playbook is a highly structured, risk-free architectural and operational guide for senior product managers and engineering leaders. We will cover exactly how to migrate your customer-facing integrations off an embedded iPaaS or visual workflow builder onto a dedicated, declarative unified API platform—without causing downtime or forcing your customers to reconnect their accounts.
What Happens When You Switch Unified API Providers
The short answer: nothing has to break. The longer answer is that four specific components are at risk during any integration provider migration, and each one needs a deliberate plan.
OAuth connections. Your customers authorized your application to access their CRM, HRIS, or ERP accounts. Those authorizations produced OAuth tokens that your current provider stores. If you can extract those tokens and inject them into the new provider, your customers never need to reconnect. If you cannot extract them, every customer sees a "Reconnect" prompt - the single biggest source of migration churn.
Data mapping schemas. Every field mapping, query translation, and response transformation you built in your current provider needs an equivalent in the new one. Missing a single custom field mapping means corrupted or incomplete data for the customers who depend on it.
Webhook subscriptions. If your current provider registered webhook endpoints with third-party APIs (Salesforce, HubSpot, etc.), those subscriptions point at your old provider's URLs. You need to either re-register them against the new provider or run a dual-receive pattern during cutover.
In-flight data. Sync jobs, queued webhook events, and pending API calls that are mid-execution during the switch need a drain plan. You cannot simply flip a switch and hope nothing was in the pipeline.
The rest of this playbook walks through each risk with prescriptive checklists, timelines, and rollback criteria so your engineering and support teams can execute a migration with minimal ambiguity.
When to Migrate
Not every frustration with your current integration layer warrants a full migration. Migrate when at least two of these conditions are true:
- Margin pressure. Your iPaaS costs grow linearly with customer API usage, and integration infrastructure now exceeds 15% of your per-customer COGS.
- Enterprise deals blocked. You have lost or stalled two or more enterprise deals in the past two quarters because prospects rejected your integration approach during security or architecture review.
- Maintenance burden. Your engineering team spends more than 30% of integration-related effort on maintaining existing connectors rather than building new ones.
- Customization ceiling. You cannot support per-customer field mappings or custom objects without code deployments.
- Scale wall. You are approaching rate limit ceilings, operation quotas, or concurrency limits on your current provider with no clear path to scale.
When to Choose Pass-Through vs Warehouse (Decision Checklist)
Many teams reach for a warehouse-centric ETL + reverse-ETL setup (extract to Snowflake or BigQuery, transform with dbt, then push back out to operational systems) when what they actually need is a declarative pass-through pipeline that reads directly from third-party APIs. The two architectures solve different problems, and mixing them up creates months of unnecessary infrastructure and steady-state cost.
Pass-through (declarative) pipelines stream data directly from third-party APIs to your application through a unified schema layer. There is no intermediate warehouse, no scheduled batch job, and no reverse-ETL job pushing rows back out. Integration behavior is expressed as configuration - JSON and JSONata - rather than as pipeline code. This is what people mean by a declarative data sync approach for SaaS: the transformation and orchestration are data, not scripts.
Warehouse-centric ETL copies raw third-party data into a data lake or warehouse, transforms it with SQL or a modeling tool, and optionally pushes results back to operational systems via reverse-ETL. It is a good fit for analytics but a poor fit for real-time application reads.
Choose pass-through when:
- Customers need real-time or near-real-time reads (dashboards, in-app workflows, search over third-party records).
- Data is customer-scoped and multi-tenant, and each tenant's data must stay logically isolated.
- You do not need to run cross-tenant analytical joins on this data.
- Latency matters more than historical depth.
- You want integration behavior to ship without a code deployment.
- Your unit economics cannot absorb per-row ETL + reverse-ETL pricing on top of application infrastructure.
Choose warehouse-centric when:
- Your product surfaces analytics, cohorts, or aggregations across all customers.
- You retain years of historical snapshots for reporting or ML training.
- Downstream consumers include BI tools, notebooks, or data science pipelines.
- Query patterns are read-heavy analytical scans that would otherwise hammer third-party APIs.
Choose both (hybrid) when:
- You have a real-time application surface AND analytics workloads on the same source data.
- Operational reads flow through pass-through; analytical reads flow through the warehouse.
- Reverse-ETL is used only for occasional bulk writes, not primary sync.
If you cannot check three or more items on the "warehouse" list, you probably do not need one. A warehouse-plus-reverse-ETL stack adds two independent failure domains between your application and the third-party API, doubles the auth and rate-limit surface area, and introduces a batch cadence that undermines the real-time UX most SaaS products actually want. A declarative pass-through pipeline eliminates both problems by removing the warehouse from the critical path.
The MVP Trap: When Make.com and iPaaS Prototypes Break at Scale
Visual workflow builders solve the "zero to one" integration problem brilliantly. You drag a webhook trigger, connect it to a Salesforce module, map some fields visually, and you have a working integration in an afternoon.
But building an integration is only 20% of the work. The other 80% is maintaining it across hundreds of tenants, dealing with API deprecations, handling rate limits, and managing custom fields.
The Margin-Killing Reality of Operation-Based Pricing
Visual workflow builders like Make.com price per operation. Every step in a visual graph consumes a task credit. This means your infrastructure costs scale linearly with your customers' API usage.
Imagine a mid-market customer signs up and wants to sync their historical HubSpot data into your platform. They have 250,000 contacts. If your iPaaS charges $0.01 per task, and your workflow requires three steps per contact (fetch, transform, load), that single historical sync just cost you $7,500. If your SaaS product charges $500/month, that one sync wiped out your margin for the entire year.
The App Sprawl and Technical Debt Crisis
According to Zylo's 2025 SaaS Management Index, which analyzed $40 billion in software spend, the average tech company now pays for 275 SaaS applications. This app sprawl creates a massive integration backlog for B2B SaaS vendors.
When you use visual builders to handle this volume, you end up with hundreds of disconnected visual graphs. There is no version control, no centralized error handling, and no easy way to roll back changes. Industry analysis highlights that engineering teams often spend up to 40% of their capacity maintaining yesterday's shortcuts and integration technical debt rather than building core product features.
B2B buyers prioritize native integrations. Research indicates that 63% of SaaS companies invest in integrations specifically to improve customer retention and unlock expansion revenue. Pointing a CIO to a Make.com template signals that your product is not enterprise-ready.
The Architectural Shift: Moving to a Declarative Integration Layer
Migrating off an iPaaS or a warehouse-centric ETL setup requires a fundamental shift in how you think about integration architecture.
Most unified API platforms and embedded iPaaS tools solve the integration problem with brute force. Behind their "unified" facade, they maintain separate code paths for each integration. They have hardcoded business logic that must be updated every time an API changes. Adding a new integration means writing new code, deploying it, and hoping it doesn't break the existing integrations.
Truto takes a radically different approach. The entire platform executes zero integration-specific code. The same code path that handles a HubSpot CRM contact listing also handles Salesforce, Pipedrive, Zoho, and Close—without knowing or caring which one it is talking to.
Integration-specific behavior is defined entirely as data: JSON configuration blobs describing the API, and JSONata expressions describing the data transformations. Because the pipeline itself is data, you can build declarative data sync pipelines without ETL tools sitting in the middle - the same configuration reads on demand, syncs on schedule, or fans out webhooks, depending on how you invoke it.
graph TD
subgraph Legacy iPaaS Architecture
A[SaaS App] --> B(Visual Workflow Builder)
B --> C{Provider Switch}
C -->|If Salesforce| D[Salesforce Node]
C -->|If HubSpot| E[HubSpot Node]
C -->|If Pipedrive| F[Pipedrive Node]
end
subgraph Declarative Unified API Architecture
G[SaaS App] --> H(Generic Execution Engine)
H --> I[(Integration Config JSON)]
H --> J[(JSONata Mapping Expressions)]
I -.-> K[Third-Party API]
J -.-> K
endThis is not an incremental improvement. It is an architectural category difference. Adding a new integration is a data operation, not a code operation. This zero integration-specific code approach is what allows you to scale to hundreds of integrations without expanding your engineering headcount.
Pre-Migration Audit Checklist
Before writing a single line of migration code, your team needs a complete inventory of your current integration state. This audit typically takes 3-5 days for a small deployment and up to two weeks for a large one.
1. OAuth Token Ownership
- Confirm you own the OAuth app registrations (client ID and client secret) for every third-party provider. If your iPaaS created these on your behalf, you may not control the credentials.
- Verify that your current provider allows exporting raw
access_token,refresh_token, andexpires_atvalues. Test this with a single account before planning the full migration. - Identify which integrations use OAuth 2.0 (portable tokens) vs. API keys (usually simpler to migrate) vs. session-based auth (may require re-authentication).
- Count the total number of connected accounts per integration, per customer. This is your migration scope.
2. Schema and Field Mapping Inventory
- Export or document every field mapping in your current provider. For each integration category (CRM, HRIS, ATS, etc.), catalog the unified fields, the source fields, and any transformation logic applied.
- Flag every custom field mapping. These are the highest-risk items during migration because they are tenant-specific.
- Document any conditional logic (if/then branches, filters, routers) in your current workflows. Each one needs an equivalent JSONata expression or configuration in the new provider.
3. Webhook Configuration Inventory
- List every webhook subscription your current provider registered with third-party APIs. Note the endpoint URL, event types, and any signing secrets.
- Determine whether your current provider or the third-party API owns the subscription lifecycle. Some providers register webhooks on your behalf and deregister them if you cancel.
- Identify which webhooks are account-specific vs. environment-wide (fan-out).
4. Rate Limit Budget Analysis
- Document the rate limits for every third-party API you integrate with. Note the quota (requests per window), window duration, and current utilization.
- Calculate whether running two providers in parallel during cutover will exceed any rate limit. If so, stagger the migration by category or throttle the old provider during the parallel-run phase.
5. Sync Job and Scheduled Task Inventory
- List every recurring sync job, its schedule, its scope (full sync vs. incremental), and the average record count per run.
- Identify which sync jobs write data back to third-party APIs (bidirectional sync) vs. read-only pulls. Bidirectional syncs carry higher risk during migration because duplicate writes can corrupt data.
6. Customer Communication Plan
- Identify which customers (if any) will experience visible changes. If the migration is fully transparent (no reconnection required), communication is optional but builds trust.
- Prepare a rollback communication template in case you need to revert mid-migration.
Step 1: Extracting OAuth Credentials and Managing the Authentication Handoff
The most terrifying part of migrating integration providers is the authentication handoff. If you do this wrong, you have to email your entire customer base asking them to click "Reconnect" on their Salesforce or QuickBooks accounts. This causes immediate churn and damages trust.
To execute a zero-downtime migration, you must programmatically extract the OAuth tokens from your iPaaS and inject them into your new unified API infrastructure.
The Extraction and Injection Process
- Audit your current token state: Export the active
access_token,refresh_token, andexpires_attimestamps from your current provider. Some legacy iPaaS tools obscure these; you may need to contact their support to get a raw database dump. - Map to the unified context schema: Truto stores credentials in a generic
contextJSON object attached to anIntegrated Accountrecord. You will format your exported tokens to match this schema. - Inject via API: Use Truto's Admin API to programmatically create the Integrated Accounts, passing the credentials directly into the context.
// Example: Injecting extracted Salesforce credentials into Truto
{
"integration_name": "salesforce",
"environment_id": "env_12345",
"tenant_id": "customer_org_99",
"context": {
"oauth": {
"token": {
"access_token": "00Dxx0000001gER!AQEAQ...",
"refresh_token": "5Aep861...",
"expires_at": "2026-10-15T14:30:00Z"
}
},
"instance_url": "https://na139.salesforce.com"
}
}Proactive Token Management
Once injected, Truto takes over the lifecycle management. The platform checks token expiration windows before every API call. If a token is within 30 seconds of expiring, the engine proactively executes the refresh flow. Additionally, the system pre-schedules refresh work 60–180 seconds before expiry to ensure high availability.
If a refresh fails (e.g., the user revoked the app in Salesforce), the account is marked as requiring re-authentication, and a webhook event is fired to your backend so you can prompt the user in your UI.
For a deeper dive into this exact sequence, review our guide on switching providers without downtime.
Step 2: Replicating iPaaS Logic with JSONata Mappings
In a visual workflow builder, data transformation looks like a tangled web of routing nodes, string manipulation blocks, and conditional branches. To migrate, you must translate this visual spaghetti into clean, declarative JSONata expressions.
JSONata is a functional query and transformation language for JSON. It is Turing-complete, side-effect free, and purpose-built for reshaping JSON objects. Truto uses it as the universal transformation engine. Every field mapping, query translation, and conditional logic block is a JSONata expression stored as a string in the database.
Transforming Responses
Let us look at how you migrate a complex CRM contact mapping. Your iPaaS might have ten different nodes to handle custom fields, flatten nested objects, and format dates. In Truto, this becomes a single, highly readable JSONata expression.
// Truto JSONata Response Mapping for a CRM Contact
(
$phone_numbers := $filter(phoneNumbers, function($v) { $v.type = "primary" });
{
"id": id,
"first_name": properties.firstname,
"last_name": properties.lastname,
"email": properties.email,
"phone": $count($phone_numbers) > 0 ? $phone_numbers[0].number : null,
"created_at": $replace(properties.createdate, "+0000", "Z"),
"company_id": associations.companies.results[0].id,
"raw_data": $
}
)Transforming Requests and Queries
The mapping layer works bidirectionally. When your SaaS application makes a request to Truto's unified API (GET /unified/crm/contacts?status=active), Truto uses JSONata to translate that query into the specific third-party format.
For example, translating status=active might result in filter [status]=Active for one API, or a complex SOQL WHERE clause for Salesforce. The runtime engine does not care what the JSONata expression does; it simply evaluates it and constructs the HTTP request.
Stop writing integration code. By moving transformation logic into JSONata strings stored in your database, you decouple integration maintenance from your core application deployment cycle. You can fix a broken Salesforce mapping instantly without waiting for a CI/CD pipeline.
Step 3: Handling API Quirks (Rate Limits, Pagination, and Webhooks)
The mark of a senior engineering team is how they handle the inevitable failures of third-party systems. Visual workflow builders often abstract these failures away poorly, leading to silent data loss or infinite retry loops that get your IP banned.
Transparent Rate Limiting
Many unified APIs attempt to be "smart" by automatically absorbing and retrying rate limit errors. This is an architectural anti-pattern. If an upstream CRM is returning HTTP 429 (Too Many Requests), your backend needs to know about it so it can pause its own internal sync queues. If the unified API hides this, your workers will continue burning CPU cycles pushing data into a black hole.
Truto enforces a radically transparent approach to rate limiting. When an upstream API returns a 429, Truto passes that exact error directly back to the caller.
However, Truto normalizes the rate limit information into standardized HTTP headers per the IETF specification:
ratelimit-limit: The total request quota.ratelimit-remaining: The remaining requests in the current window.ratelimit-reset: The timestamp when the quota resets.
Your application retains complete control over its retry and exponential backoff strategies, armed with normalized data regardless of whether the upstream API uses headers, JSON bodies, or custom formats to communicate its limits.
Declarative Pagination
Pagination logic is notoriously fragmented across SaaS APIs. Some use cursor-based pagination, others use offsets, and some rely on HTTP Link headers.
Truto handles this declaratively. The integration configuration defines the pagination format (cursor, page, offset, link_header). When you call a unified list endpoint, Truto applies the correct strategy automatically, extracting the next page token from the response and returning a standardized next_cursor to your application.
Unified Webhook Ingestion
Moving off an iPaaS means you need a new way to ingest real-time events. Truto acts as a unified webhook receiver. When a third-party service fires a webhook, Truto executes a precise pipeline:
- Verification: Validates the cryptographic signature (HMAC, JWT, Basic Auth) using timing-safe comparisons.
- Payload Transform: Applies a JSONata expression to normalize the raw payload.
- Event Mapping: Translates provider-specific events (e.g.,
employee.joined) into standardized unified events (e.g.,record:createdonhris/employees). - Enrichment: Optionally fetches the full resource data if the webhook payload only contained an ID.
- Delivery: Enqueues the normalized event for delivery to your configured endpoints.
This pipeline supports both account-specific webhooks and environment-level fan-out architectures, ensuring you receive a consistent payload shape regardless of the source.
Step 4: Supporting Per-Customer Customizations with the 3-Level Override Hierarchy
The most common reason enterprise deals stall is custom fields. Your prospect uses Salesforce, but they have heavily modified their Account object with custom fields specific to their industry. Your hardcoded iPaaS template expects standard fields and breaks.
If you use a traditional unified API, you are forced to map these custom fields into a generic remote_data blob, pushing the parsing logic back onto your application code.
Truto solves this via a 3-Level Override Hierarchy. This system allows you to customize API mappings on a per-customer basis without touching source code.
Level 1: Platform Base
This is the default mapping provided by Truto. It translates standard Salesforce fields to the unified CRM model. It works perfectly for 80% of your customers.
Level 2: Environment Override
You can apply overrides at the environment level (e.g., Staging vs. Production). If your staging environment needs to route requests to a sandbox API endpoint, you apply a JSONata override here. It deep-merges on top of the Platform Base.
Level 3: Account Override
This is the breakthrough feature for enterprise sales. Individual connected accounts can have their own mapping overrides.
If "Enterprise Corp" needs their custom x_industry_type_c Salesforce field mapped to your application's vertical field, you simply apply a JSONata override directly to their Integrated Account record.
// Account-level override for Enterprise Corp
{
"response_mapping": {
"vertical": "x_industry_type_c"
}
}The runtime engine deep-merges this override at execution time. Only Enterprise Corp's data is affected. You just solved a custom enterprise integration requirement without deploying a single line of code. For more details on this architecture, read our guide on per-customer API mappings.
Step-by-Step Migration Plan with Milestones
Whether you are moving from Make.com to a unified API, or from a warehouse-plus-reverse-ETL stack to a declarative pass-through pipeline, the migration follows the same nine milestones. Each is a discrete gate. Do not proceed until the previous milestone is signed off by a named owner.
Milestone 1: Audit complete. Every OAuth credential, mapping, webhook subscription, and sync job is documented. See the pre-migration audit checklist above. Exit criteria: audit spreadsheet reviewed by engineering lead and support lead.
Milestone 2: Target architecture ratified. Product, engineering, and finance have agreed on pass-through vs warehouse vs hybrid. Cost projections and latency SLAs are in writing. Exit criteria: signed architecture decision record.
Milestone 3: OAuth token export path proven. You have successfully extracted and re-injected credentials for one test account per integration without triggering a re-authentication prompt. Exit criteria: 100% of test accounts refresh cleanly on the new provider.
Milestone 4: Mapping translation complete for the first category. JSONata expressions cover 100% of the fields used by your application for the chosen starter category (usually CRM or HRIS). Exit criteria: unit tests pass against recorded upstream fixtures.
Milestone 5: Parallel-run infrastructure live. Dual-receive webhooks and shadow-mode API calls are recording responses from both providers. A parity dashboard is instrumented. Exit criteria: dashboard shows at least 24 hours of continuous data from both providers.
Milestone 6: First category cutover complete. One category is fully migrated, validated for at least 30 days, and all rollback triggers have remained green. Exit criteria: on-call rotation reports zero P1 or P2 incidents attributable to the new provider.
Milestone 7: Backfill executed. Historical data (if required) is loaded into the new provider or into your application's storage via the pass-through pipeline. Exit criteria: record counts match expected volumes within 1% tolerance.
Milestone 8: Remaining categories cut over. Each subsequent category follows the same parallel-run + cutover + validation sequence. Exit criteria: every category has passed its go/no-go checklist.
Milestone 9: Old provider decommissioned. After 30 days of stability across all categories, the old provider is downgraded or cancelled and its configuration is archived. Exit criteria: postmortem published and cost delta measured across two billing cycles.
Milestones without owners slip. Assign an engineer, a product manager, and a support lead to each one.
Parallel-Run Architecture and the Dual-Receive Pattern
The safest way to migrate between integration providers is to run both systems simultaneously for a defined period, compare their outputs, and cut over only when the new provider matches the old one within your tolerance thresholds. This is a well-established practice in zero-downtime migrations - incremental, phased deployment that minimizes risk and allows continuous monitoring.
The Dual-Receive Pattern for Webhooks
During the parallel-run phase, both providers need to receive webhook events from the same third-party sources. There are two approaches:
Option A: Dual subscription. Register webhook endpoints for both providers with the third-party API. Both receive the same events independently. This is the simplest approach but doubles your webhook volume and may trigger rate limits on providers that throttle subscription counts.
Option B: Fanout proxy. Deploy a lightweight HTTP proxy that receives webhooks from third-party APIs and forwards each payload to both providers. This keeps a single subscription per source but adds an infrastructure dependency.
graph LR
A[Third-Party API] -->|webhook| B(Fanout Proxy)
B -->|forward| C[Old Provider]
B -->|forward| D[New Provider]
C -->|deliver| E[Your Backend]
D -->|deliver| EYour backend receives events from both providers during the parallel-run window. Tag each event with its source so you can compare payloads and detect discrepancies.
Shadow Mode for API Calls
For unified API calls (list, get, create, update), run the new provider in shadow mode:
- Your application sends every API request to your old provider as normal.
- A background process replays the same request against the new provider.
- A comparison job diffs the responses and logs any field-level discrepancies.
Shadow mode must be read-only. Do not replay create, update, or delete operations against the new provider until you are ready to cut over. Duplicate writes to third-party APIs can cause data corruption that is extremely difficult to untangle.
Parallel-Run Duration
Run the parallel phase for a minimum of one full business cycle per integration category. For most B2B integrations, that means at least one full week to capture weekday and weekend patterns. For payroll or monthly reporting integrations, run for a full calendar month.
Category-by-Category Cutover Checklist
Never migrate all integration categories simultaneously. Cut over one category at a time, starting with the lowest-risk one.
Recommended Cutover Sequence
- Read-only integrations first. Categories where your product only reads data (e.g., pulling contacts from a CRM) carry the lowest risk because a bad mapping only affects display, not third-party data.
- Low-volume categories second. Integrations with fewer connected accounts and lower API call frequency give you more room to catch and fix issues.
- Bidirectional sync last. Categories where your product both reads and writes data (e.g., creating deals in a CRM, updating employee records in an HRIS) carry the highest risk and should only move after you have built confidence with the earlier categories.
Per-Category Steps
For each integration category, execute the following sequence:
- Complete the parallel-run for this category with zero critical discrepancies for the required duration.
- Freeze schema changes on the old provider for this category. No mapping updates during cutover.
- Drain in-flight work. Wait for all pending sync jobs and queued webhook events on the old provider to complete.
- Switch routing. Point your application's API calls for this category to the new provider.
- Verify webhook delivery. Confirm the new provider is receiving and delivering webhook events for this category within your latency SLA.
- Run parity validation against live data for at least 24 hours.
- Deregister old webhook subscriptions for this category only after the validation window passes.
- Mark category as migrated in your internal tracking.
Go/No-Go Criteria
Define these before you start. A category is ready for cutover when:
- Parallel-run parity score is above 99.5% for response shape and field values.
- Zero sustained authentication failures on the new provider for accounts in this category.
- Webhook delivery latency on the new provider is within 2x of the old provider's baseline.
- At least one full business cycle of shadow mode data has been reviewed and approved.
Backfill and Replay Strategies for Large Datasets
Migration playbooks often skip the hardest problem: what happens to the years of historical data already synced through your old pipeline? You have three viable strategies.
Strategy 1: No backfill (delta-only). The new provider only handles data changed after the cutover date. Historical data stays in your application's existing storage, tagged as "sourced from old provider." This is the fastest option and works when your product does not need historical context beyond what is already persisted.
Strategy 2: Bounded backfill. Replay the last N days or N months of data through the new provider. Choose the window based on your product's actual read patterns - most operational workloads only need the last 90 days. Run the backfill as a paginated, throttled job that respects the third-party's rate limits.
Strategy 3: Full historical replay. Replay all data from the beginning of time. Only do this when your product surfaces historical records directly and cannot reconstruct them from your existing database. Full replays are slow, cost-heavy, and rate-limit-bound.
Backfill Mechanics
For any backfill larger than a few thousand records, follow these rules:
- Chunk by time or ID range. Break the backfill into deterministic chunks (e.g., one week of records per job) so a failure only requires re-running one chunk.
- Respect the rate limit budget. Reserve at least 50% of the third-party's rate limit quota for live traffic. Backfills consume the remaining budget.
- Persist a resume cursor. Every completed chunk writes its cursor to durable storage. If the backfill process dies, it resumes from the last cursor, not from the beginning.
- Idempotent writes. Every backfill write must be safe to replay. Use the third-party record ID as the idempotency key so duplicate runs do not create duplicate rows.
- Isolate from live traffic. Route backfill traffic through a separate queue or worker pool so a stuck backfill cannot starve real-time syncs.
- Cap concurrency per account. Even if the global rate limit has room, per-account limits or upstream throttling can slow individual tenants. A concurrency cap of 2-4 requests per account is a safe default.
Replaying Webhook Events
For webhook-driven data, replay is trickier because most third-party APIs do not offer historical webhook delivery. Two options:
Option A: Poll-based replay. Use the third-party's list endpoints with a modified_since filter to reconstruct what would have been webhooked. This is the most reliable approach and the one to default to.
Option B: Persisted event log. If your old provider retained raw webhook payloads, export them and replay them through the new provider's normalization pipeline. Only viable if the old provider stored raw payloads (many do not).
Truto's ingestion pipeline is idempotent at the event level - replaying the same third-party event ID does not produce duplicate downstream deliveries. This means you can replay aggressively during a backfill without worrying about double-processing on your application side.
Progress Tracking
Expose backfill progress to your operations team as a per-tenant, per-category counter: total records expected, records fetched, records written, records failed. Without this, a backfill that stalls at 40% completion looks identical to one that finished. Make progress observable.
Validation Checks and Parity Tests
Parity testing is the difference between a confident migration and a prayer. Run these checks during the parallel-run phase and again immediately after each category cutover.
Response Shape Validation
For every unified API endpoint in the migrating category, compare the response schema from both providers:
- Same top-level fields present in both responses.
- Same data types for each field (string vs. number vs. array).
- Same pagination behavior (
next_cursorformat, page sizes, total counts). - Same
nullvs. absent field behavior for optional fields.
Field-Level Data Parity
For a statistically meaningful sample of records (minimum 500 or 10% of total records, whichever is larger):
- Compare field values between old and new provider responses for the same third-party record.
- Flag any field where values differ. Investigate whether the difference is a mapping error, a data freshness issue, or an intentional improvement in the new mapping.
- Pay special attention to: date/time formats and timezone handling, enum values (string casing, naming conventions), phone number formatting, and custom field handling.
Webhook Payload Parity
For every webhook event type in the migrating category:
- Compare the normalized payload structure from both providers.
- Verify that event type names match your application's expected values.
- Confirm that timestamps, record IDs, and changed fields are present and correctly formatted.
Error Handling Parity
Deliberately trigger common error conditions and compare how both providers surface them:
- Invalid or expired OAuth token (expect 401).
- Rate limit exceeded (expect 429 with normalized headers).
- Nonexistent record ID (expect 404).
- Malformed request body (expect 400 with a descriptive error message).
Testing with Live Accounts
Do not rely solely on sandbox accounts. Test with at least 3-5 live production accounts per integration (with the customer's consent) during the parallel-run phase. Sandbox environments frequently behave differently from production - different rate limits, different field configurations, different data volumes. Your parity tests need to reflect reality.
Testing Matrix and Validation Queries
Parity testing needs structure so you know what has been covered and what has not. Build a matrix - a spreadsheet, a test fixture repo, or a dedicated table in your migration tracker - keyed by (integration, category, endpoint, scenario).
| Dimension | Values to cover |
|---|---|
| Integration | Every provider in the migrating category (Salesforce, HubSpot, Pipedrive, etc.) |
| Endpoint | list, get, create, update, delete, custom actions |
| Field type | Standard fields, custom fields, nested objects, arrays, enums, timestamps |
| Auth state | Valid token, expired token, revoked token, insufficient scope |
| Data volume | Empty result, 1 record, page-sized, multi-page cursor |
| Error path | 400, 401, 403, 404, 429, 5xx |
| Webhook event | create, update, delete, non-record events (if applicable) |
Every cell in this matrix needs at least one automated test or a documented manual verification step before the category is eligible for cutover. Empty cells are the ones that bite you in production.
Validation Queries
Once data is flowing through the new provider, run these validation queries on your application's database daily during the parallel-run phase and weekly for 30 days after cutover.
1. Record count parity by tenant.
-- Compare record counts by tenant between old and new provider sources
SELECT tenant_id, source_provider, COUNT(*) AS record_count
FROM crm_contacts
WHERE synced_at > NOW() - INTERVAL '24 hours'
GROUP BY tenant_id, source_provider
ORDER BY tenant_id;Any tenant where old and new counts differ by more than 1% needs investigation.
2. Field completeness regression.
-- Find fields where the new provider produces nulls that the old provider populated
SELECT field_name,
SUM(CASE WHEN source_provider = 'old' AND value IS NOT NULL THEN 1 ELSE 0 END) AS old_populated,
SUM(CASE WHEN source_provider = 'new' AND value IS NOT NULL THEN 1 ELSE 0 END) AS new_populated
FROM crm_contact_fields
WHERE synced_at > NOW() - INTERVAL '24 hours'
GROUP BY field_name
HAVING SUM(CASE WHEN source_provider = 'old' AND value IS NOT NULL THEN 1 ELSE 0 END)
> SUM(CASE WHEN source_provider = 'new' AND value IS NOT NULL THEN 1 ELSE 0 END) * 1.05;3. Webhook delivery drift.
-- Detect events delivered by one provider but not the other during the parallel-run window
SELECT third_party_event_id,
MAX(CASE WHEN source_provider = 'old' THEN 1 ELSE 0 END) AS from_old,
MAX(CASE WHEN source_provider = 'new' THEN 1 ELSE 0 END) AS from_new
FROM webhook_events
WHERE received_at > NOW() - INTERVAL '1 hour'
GROUP BY third_party_event_id
HAVING MAX(CASE WHEN source_provider = 'old' THEN 1 ELSE 0 END)
!= MAX(CASE WHEN source_provider = 'new' THEN 1 ELSE 0 END);4. Auth health check.
-- Accounts whose tokens have not refreshed successfully in the last 24 hours
SELECT tenant_id, integration, last_refresh_at, refresh_error_count
FROM integrated_accounts
WHERE last_refresh_at < NOW() - INTERVAL '24 hours'
OR refresh_error_count > 0;5. Backfill progress.
-- Per-tenant backfill completeness
SELECT tenant_id, integration,
records_expected, records_written,
ROUND(100.0 * records_written / NULLIF(records_expected, 0), 2) AS pct_complete
FROM backfill_progress
WHERE completed_at IS NULL
ORDER BY pct_complete ASC;Wire the results of these queries into your migration dashboard. If any query returns unexpected rows, pause the next cutover until the root cause is understood.
Rollback and Contingency Plan
Define your rollback plan before the migration starts. If you wait until something breaks to figure out how to revert, you will make the situation worse under pressure.
Rollback Triggers
Agree on these with your engineering and support teams before cutover begins. Initiate a rollback if any of the following occur during the validation window:
- Authentication failure rate for the migrated category exceeds 5% of connected accounts.
- Webhook delivery success rate drops below 95% for more than 30 minutes.
- More than 3 customer-reported data discrepancies within the first 24 hours.
- Any data corruption in a bidirectional sync (duplicate records created, fields overwritten with incorrect values).
How to Roll Back
- Re-route your application's API calls for the affected category back to the old provider.
- Re-enable webhook subscriptions on the old provider if you deregistered them.
- Drain any queued events on the new provider to prevent duplicate delivery when you eventually re-migrate.
- Audit the affected time window: identify every API call and webhook event that was processed by the new provider during the failed cutover, and verify data integrity in your application's database.
Keep the Old Provider Warm
Do not cancel your old provider's account or delete its configuration until every category has been migrated and validated for a minimum of 30 days. The cost of maintaining a dormant account is trivially small compared to the cost of an unrecoverable rollback.
Sample Migration Timelines
These estimates assume a team of 2-3 engineers working on the migration and include the parallel-run phase. Actual timelines vary based on the complexity of your custom mappings and the number of bidirectional sync integrations.
| Factor | Small | Medium | Large |
|---|---|---|---|
| Connected accounts | < 50 | 50 - 500 | 500+ |
| Integration categories | 1 - 2 | 3 - 5 | 6+ |
| Custom field mappings | Minimal | Moderate | Heavy per-tenant customization |
| Pre-migration audit | 3 - 5 days | 1 - 2 weeks | 2 - 3 weeks |
| Token extraction and injection | 1 - 2 days | 3 - 5 days | 1 - 2 weeks |
| Mapping translation | 1 week | 2 - 3 weeks | 4 - 6 weeks |
| Parallel-run per category | 1 week | 1 - 2 weeks | 2 - 4 weeks |
| Category cutover + validation | 2 - 3 days per category | 3 - 5 days per category | 1 - 2 weeks per category |
| Total elapsed time | 3 - 5 weeks | 6 - 12 weeks | 12 - 24 weeks |
These timelines assume your current provider allows OAuth token export. If you cannot extract tokens and must ask customers to reconnect, add 2-4 weeks for customer communication, re-authentication flows, and follow-up with unresponsive accounts.
Monitoring and Metrics During Cutover
Instrument your application and the new provider's API with the following metrics before you begin the first category cutover. If you do not have baseline numbers from your old provider, measure them during the parallel-run phase.
| Metric | What to Track | Alert Threshold |
|---|---|---|
| API error rate | 4xx and 5xx responses per integration, per category | > 2x baseline for 10+ minutes |
| Auth failure rate | 401 responses as a percentage of total requests | > 5% of accounts in any 1-hour window |
| Webhook delivery success | Percentage of events successfully delivered to your endpoints | < 95% for any 30-minute window |
| Webhook delivery latency | Time from third-party event to delivery at your endpoint | p95 > 2x baseline |
| API response latency | p50, p95, p99 response times for unified API calls | p95 > 3x baseline |
| Token refresh failure rate | Failed OAuth token refreshes as a percentage of total refreshes | Any failure sustained for > 5 minutes |
| Data freshness lag | Time between a record changing in the third-party API and reflecting in your application | > 2x baseline for incremental syncs |
Build a migration dashboard that surfaces these metrics per category and per integration. Review it at the start and end of each business day during active cutover periods.
Operational Runbook: Auth, Rate Limits, Retries, and Monitoring
Once you have cut over to a declarative pass-through pipeline, day-two operations decide whether the new integration surface is stable or a constant on-call burden. Codify the following procedures before the first category goes live.
OAuth and Authentication Incidents
Symptom: Sustained 401 errors on a specific integration or a specific account.
Diagnostic steps:
- Scope the failure: one account (revoked app), one integration (provider-wide OAuth outage), or all accounts (your client ID/secret rotation issue)?
- Attempt a manual refresh against the third-party's token endpoint using the stored refresh token.
- If the refresh returns
invalid_grant, the token is dead. Mark the account as requiring re-authentication and emit a webhook to your backend so the customer can be prompted. - If the refresh works, the failure is likely a scope or permission change on the third-party side. Verify the OAuth scopes granted against what your integration requires.
- If all accounts fail simultaneously, check whether the OAuth app credentials themselves were rotated or revoked in the third-party developer console.
Prevention: Truto refreshes tokens well ahead of expiry (typically 60-180 seconds before the expires_at timestamp) and again at request time if the token is within 30 seconds of expiring. Tune this window based on your latency tolerance and the third-party's clock skew behavior.
Rate Limit Incidents
Symptom: 429 responses on a specific integration, or backfill jobs slowing to a crawl.
Diagnostic steps:
- Check the normalized
ratelimit-remainingandratelimit-resetheaders on the failing response. - Confirm whether the rate limit is per-account, per-app, or per-IP. Salesforce and HubSpot typically enforce per-app quotas; NetSuite enforces per-account.
- If per-app, coordinate across all connected accounts - one runaway tenant can starve everyone else.
- Reduce concurrency, increase backoff intervals, or shift non-urgent work (backfills, reporting sweeps) to off-peak hours.
Prevention:
- Set a concurrency cap per integration per account.
- Use exponential backoff with jitter on retries. Never retry a 429 immediately.
- Reserve rate-limit budget for user-initiated reads. Bulk jobs get the remainder.
- Alert when sustained usage crosses 70% of the quota so you have room to investigate before hitting a ceiling.
Retry Strategy
Not every error should be retried. Use this decision table for outbound calls to third-party APIs:
| HTTP status | Retry? | Strategy |
|---|---|---|
| 400, 422 | No | Client error. Log and surface to caller. |
| 401 | Once, after token refresh | If the refresh fails, mark account for re-auth. |
| 403 | No | Permission issue. Do not retry. |
| 404 | No | Resource does not exist. |
| 408, 429, 502, 503, 504 | Yes | Exponential backoff with jitter, capped at 5 retries. |
| 500 | Yes, cautiously | Backoff, but circuit-break after 3 consecutive failures. |
| Network error / timeout | Yes | Backoff, treat like 5xx. |
Circuit breakers should trip on sustained failures (for example, 10 consecutive 5xx responses from the same integration within 60 seconds) and require an explicit half-open probe before resuming full traffic. Without a circuit breaker, one failing upstream can consume your entire worker pool.
Monitoring Beyond the Cutover
The metrics table from the cutover phase becomes your steady-state SLO dashboard. Beyond those, track:
- Configuration drift. Any hand-edited JSONata expressions in production without a corresponding pull request. Every mapping change should flow through code review.
- Custom override coverage. Number of accounts with account-level mapping overrides and their last-modified timestamps. Stale overrides often indicate a churned customer or a mapping that could be promoted to the platform base.
- Silent success errors. Requests that returned 200 but with empty or malformed bodies. These are the hardest failures to detect and require content-based checks, not status-code checks.
- Idempotency key collisions. Retries that would have created duplicates but were correctly deduped. A rising rate here usually indicates a broken upstream that is timing out mid-write.
Incident Response Playbook
When a customer-facing incident occurs on the new pipeline:
- Acknowledge within 5 minutes. Post to your internal incident channel with the affected integration, tenant scope, and blast radius estimate.
- Classify: is this an upstream provider outage, a mapping regression, an auth issue, or an internal platform issue? Different categories have different owners.
- If mapping-related, revert the most recent mapping change for the affected category. Because mappings are data, revert is a configuration operation, not a deployment.
- If auth-related, run the auth diagnostic steps above and communicate expected recovery time to affected customers.
- If upstream-related, subscribe to the provider's status page and mirror updates to your own status page.
- Publish a postmortem within 5 business days. Include the mapping diff or config change if applicable.
Post-Migration Postmortem Checklist
After every category has been migrated, validated, and stable for 30 days, run a formal postmortem. This captures institutional knowledge and surfaces integration debt that accumulated during the migration.
Decommission the Old Provider
- Cancel or downgrade your old provider's account.
- Remove old provider SDK dependencies from your codebase.
- Delete old provider webhook endpoints from third-party API dashboards.
- Archive (do not delete) old provider configuration and mapping documentation for reference.
Validate Cost Impact
- Compare monthly integration infrastructure cost (old vs. new) for at least two full billing cycles.
- Calculate the actual per-customer integration cost under the new provider.
- Verify that high-volume sync operations (historical imports, bulk exports) no longer produce cost spikes.
Update Documentation
- Update internal runbooks to reference the new provider's APIs, dashboards, and support channels.
- Update customer-facing integration documentation and setup guides.
- Update your status page to reflect the new provider's dependency.
Capture Lessons Learned
- Document every mapping discrepancy found during parity testing and how it was resolved.
- Record the actual migration timeline vs. the estimated timeline, with reasons for any overruns.
- Note any third-party API quirks discovered during migration that should inform future integration work.
- Identify which parts of the migration could be automated for future environment or region migrations.
The ROI of Migrating: Reclaiming Engineering Capacity
Migrating off a visual workflow builder or a warehouse-plus-reverse-ETL stack is a strategic infrastructure upgrade. The return on investment is measured in three distinct categories:
1. Margin Protection: By eliminating operation-based pricing models, your infrastructure costs scale predictably with your compute usage, not linearly with your customers' API traffic. You can confidently support high-volume historical data syncs without destroying your unit economics.
2. Engineering Velocity: Reclaiming the 40% of engineering capacity spent maintaining visual workflow technical debt allows your team to focus on core product features. Adding a new integration becomes a configuration task, not a sprint commitment.
3. Enterprise Revenue Unblocked: When a CIO asks how you integrate with their heavily customized ERP or CRM, you no longer point them to a Zapier link. You offer a native, white-labeled integration experience that handles their custom fields flawlessly, passes their security review, and keeps them fully within your application's UI.
The migration requires discipline, specifically around the OAuth credential handoff and translating visual logic into JSONata. But once the declarative architecture is in place, your integration layer transforms from a fragile liability into a lasting competitive advantage.
FAQ
- Why is Make.com bad for customer-facing SaaS integrations?
- Make.com is excellent for internal ops, but its operation-based pricing destroys SaaS margins at scale. It also lacks version control and programmatic override capabilities needed for multi-tenant enterprise custom fields.
- How do you migrate OAuth tokens from an iPaaS without downtime?
- You programmatically extract the active access and refresh tokens from your iPaaS database and inject them directly into your new unified API's token management system, bypassing the need for users to re-authenticate.
- How does Truto handle third-party API rate limits?
- Truto normalizes upstream rate limit data into standard IETF HTTP headers but passes 429 Too Many Requests errors directly back to your application, ensuring you retain full control over retry and backoff queues.
- Can I customize API mappings for a single enterprise customer?
- Yes. Truto utilizes a 3-level override hierarchy that allows you to apply JSONata mapping overrides to specific integrated accounts, handling custom fields without changing your core codebase.