[{"data":1,"prerenderedAt":739},["ShallowReactive",2],{"route-doc-meta:\u002Fmigrate":3,"migrate-overview-content":4},null,{"id":5,"title":6,"body":7,"description":732,"extension":733,"meta":734,"navigation":651,"path":735,"seo":736,"stem":737,"__hash__":738},"content\u002Fmigrate\u002Foverview.md","Migrate to Unified.to",{"type":8,"value":9,"toc":719},"minimark",[10,14,18,21,66,76,81,84,286,290,297,300,335,339,344,361,365,401,405,408,425,436,565,572,576,588,598,602,629,633,636,640,702,715],[11,12,6],"h1",{"id":13},"migrate-to-unifiedto",[15,16,17],"p",{},"Moving from another unified API is mostly a translation exercise. The categories, objects and CRUD operations you already use map onto Unified.to one to one, and your end users' third-party accounts stay where they are. What changes is how you identify a connection, how you page through lists, and how you receive changes.",[15,19,20],{},"Pick your current provider for a side-by-side guide covering authorization, API calls, pagination, webhooks and passthrough:",[22,23,24,34,42,50,58],"grid",{},[25,26,27],"gridhightlight",{},[15,28,29],{},[30,31,33],"a",{"href":32},"\u002Fmigrate\u002Fmerge","Migrate from Merge",[25,35,36],{},[15,37,38],{},[30,39,41],{"href":40},"\u002Fmigrate\u002Fapideck","Migrate from Apideck",[25,43,44],{},[15,45,46],{},[30,47,49],{"href":48},"\u002Fmigrate\u002Fkombo","Migrate from Kombo",[25,51,52],{},[15,53,54],{},[30,55,57],{"href":56},"\u002Fmigrate\u002Ffinch","Migrate from Finch",[25,59,60],{},[15,61,62],{},[30,63,65],{"href":64},"\u002Fmigrate\u002Frutter","Migrate from Rutter",[15,67,68,69,75],{},"Moving from a provider that isn't listed, or from integrations you built in-house? The plan below still applies. ",[30,70,74],{"href":71,"rel":72},"https:\u002F\u002Funified.to\u002Fcontact",[73],"nofollow","Contact us"," and we'll help you map your current setup.",[77,78,80],"h2",{"id":79},"what-changes","What changes",[15,82,83],{},"Most unified APIs share the same building blocks under different names. This table maps the common ones to Unified.to. Each provider guide has an exact mapping.",[85,86,87,103],"table",{},[88,89,90],"thead",{},[91,92,93,97,100],"tr",{},[94,95,96],"th",{},"Concept",[94,98,99],{},"Typical unified API",[94,101,102],{},"Unified.to",[104,105,106,122,137,151,166,188,210,238,256,271],"tbody",{},[91,107,108,112,115],{},[109,110,111],"td",{},"An end user's authorized account",[109,113,114],{},"Linked account, consumer connection, integration, connection",[109,116,117,121],{},[118,119,120],"strong",{},"Connection",", identified by a connection ID",[91,123,124,127,130],{},[109,125,126],{},"Selecting the account on a request",[109,128,129],{},"A per-account token or ID sent in a header",[109,131,132,133],{},"The connection ID in the URL path: ",[134,135,136],"code",{},"\u002F{category}\u002F{connection_id}\u002F{object}",[91,138,139,142,145],{},[109,140,141],{},"Authenticating your server",[109,143,144],{},"API key, sometimes plus app or account headers",[109,146,147,148],{},"One workspace API key: ",[134,149,150],{},"Authorization: Bearer {API_KEY}",[91,152,153,156,159],{},[109,154,155],{},"End-user authorization UI",[109,157,158],{},"Link \u002F Vault \u002F Connect widget with a token exchange",[109,160,161,165],{},[30,162,164],{"href":163},"\u002Fconcepts\u002Fembedded-components","Authorization component"," or auth URL; no token exchange",[91,167,168,171,174],{},[109,169,170],{},"Pagination",[109,172,173],{},"Cursor",[109,175,176,179,180,183,184,187],{},[134,177,178],{},"limit"," and ",[134,181,182],{},"offset"," (",[30,185,170],{"href":186},"\u002Freference\u002Fpagination",")",[91,189,190,193,205],{},[109,191,192],{},"Incremental reads",[109,194,195,198,199,198,202],{},[134,196,197],{},"modified_after",", ",[134,200,201],{},"updated_after",[134,203,204],{},"filter[updated_since]",[109,206,207],{},[134,208,209],{},"updated_gte",[91,211,212,215,224],{},[109,213,214],{},"Vendor-specific fields",[109,216,217,198,220,223],{},[134,218,219],{},"remote_data",[134,221,222],{},"_raw",", custom field mappings",[109,225,226,229,230,233,234,187],{},[134,227,228],{},"raw"," via the ",[134,231,232],{},"fields"," parameter (",[30,235,237],{"href":236},"\u002Freference\u002Ffields","Custom & original fields",[91,239,240,243,246],{},[109,241,242],{},"Endpoints outside the data model",[109,244,245],{},"Passthrough \u002F proxy endpoint",[109,247,248,252,253],{},[30,249,251],{"href":250},"\u002Fpassthrough\u002Foverview","Passthrough API",": ",[134,254,255],{},"\u002Fpassthrough\u002F{connection_id}\u002F{path}",[91,257,258,261,264],{},[109,259,260],{},"Change notifications",[109,262,263],{},"Webhooks fired after a scheduled sync",[109,265,266,270],{},[30,267,269],{"href":268},"\u002Freference\u002Fwebhooks","Native and virtual webhooks"," that carry the changed records",[91,272,273,276,279],{},[109,274,275],{},"Where data lives",[109,277,278],{},"Often a synced copy in the provider's database",[109,280,281,282,187],{},"Nowhere: requests go to the source API in real time (",[30,283,285],{"href":284},"\u002Fconcepts\u002Farchitecture","Architecture",[77,287,289],{"id":288},"from-a-synced-copy-to-real-time","From a synced copy to real-time",[15,291,292,293,296],{},"Several unified APIs sync your customers' data into their own database on a schedule and serve your reads from that copy. Unified.to is a ",[30,294,295],{"href":284},"real-time pass-through API",": every request goes to the source API and returns current data, and no end-customer data is stored at rest on our side.",[15,298,299],{},"In practice this means:",[301,302,303,310,316,326],"ul",{},[304,305,306,309],"li",{},[118,307,308],{},"There's no initial sync to wait for."," A new connection can be read as soon as authorization finishes.",[304,311,312,315],{},[118,313,314],{},"Writes reach the source immediately",", and the response reflects the source's result.",[304,317,318,321,322,325],{},[118,319,320],{},"You decide what to store."," If your product needs a local copy, keep it in your own database and keep it current with ",[30,323,324],{"href":268},"webhooks",". Webhooks deliver the changed records in the payload, not a pointer to fetch them.",[304,327,328,331,332,334],{},[118,329,330],{},"Reads cost source API calls."," Read incrementally with ",[134,333,209],{}," or webhooks rather than re-reading full lists on every request.",[77,336,338],{"id":337},"migration-plan","Migration plan",[340,341,343],"h3",{"id":342},"_1-inventory-what-you-use","1. Inventory what you use",[15,345,346,347,351,352,355,356,360],{},"List the categories, objects, fields and write operations your code depends on, plus every webhook event you consume. Then check each integration's coverage on ",[30,348,350],{"href":349},"\u002Fintegrations","Supported integrations"," or in the integration's ",[118,353,354],{},"Feature Support"," tab in the dashboard. If something you rely on is missing, ",[30,357,359],{"href":71,"rel":358},[73],"tell us"," before you start. Most gaps can be closed by adding the capability to the unified API.",[340,362,364],{"id":363},"_2-set-up-your-workspace","2. Set up your workspace",[366,367,368,386,393],"ol",{},[304,369,370,371,376,377,381,382,385],{},"Create an account at ",[30,372,375],{"href":373,"rel":374},"https:\u002F\u002Fapp.unified.to\u002Flogin",[73],"app.unified.to"," in the ",[30,378,380],{"href":379},"\u002Freference\u002Frest#api-urls","data region"," you need, and copy your API key and workspace ID from ",[118,383,384],{},"Settings > API Keys",".",[304,387,388,389,392],{},"Activate the same integrations in your ",[118,390,391],{},"Production"," environment. Use your own OAuth app credentials for each vendor. If you already registered OAuth apps with vendors for your current provider, you can reuse them: add Unified.to's redirect URI to each app and enter the client ID and secret in the dashboard.",[304,394,395,396,400],{},"Request the ",[30,397,399],{"href":398},"\u002Fconcepts\u002Fscopes","scopes"," your code needs, and no more.",[340,402,404],{"id":403},"_3-move-your-connections","3. Move your connections",[15,406,407],{},"You have two options, and you can mix them per integration.",[15,409,410,413,414,416,417,420,421,424],{},[118,411,412],{},"Re-authorize."," Add the ",[30,415,164],{"href":163}," to your app and ask each customer to reconnect. Pass your own user or account ID as ",[134,418,419],{},"external_xref"," (or ",[134,422,423],{},"state",") so you can link the new connection ID to the right customer. Plenty of teams do this gradually: new customers go through Unified.to, and existing customers are prompted to reconnect when they next open the integrations page.",[15,426,427,430,431,435],{},[118,428,429],{},"Import existing credentials."," If you hold the credentials for a connection, such as OAuth tokens issued to your own OAuth app or an API key the customer gave you, create the connection directly with ",[30,432,434],{"href":433},"\u002Funified\u002Fconnection\u002FCreate_connection","Create connection"," and your customer never has to reconnect. Some providers can export tokens on request, but only tokens issued to an OAuth app you own will keep refreshing after you switch.",[437,438,443],"pre",{"className":439,"code":440,"language":441,"meta":442,"style":442},"language-bash shiki shiki-themes github-dark github-dark github-light","curl -X POST https:\u002F\u002Fapi.unified.to\u002Funified\u002Fconnection \\\n  -H \"Authorization: Bearer $UNIFIED_API_KEY\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"integration_type\": \"hubspot\",\n    \"categories\": [\"crm\"],\n    \"permissions\": [\"crm_contact_read\", \"crm_contact_write\"],\n    \"external_xref\": \"customer_123\",\n    \"auth\": {\n      \"access_token\": \"…\",\n      \"refresh_token\": \"…\",\n      \"expiry_date\": \"2026-10-01T00:00:00Z\"\n    }\n  }'\n","bash","",[134,444,445,468,486,496,505,511,517,523,529,535,541,547,553,559],{"__ignoreMap":442},[446,447,450,454,458,462,465],"span",{"class":448,"line":449},"line",1,[446,451,453],{"class":452},"s5n6i","curl",[446,455,457],{"class":456},"sXWYR"," -X",[446,459,461],{"class":460},"s4Y1p"," POST",[446,463,464],{"class":460}," https:\u002F\u002Fapi.unified.to\u002Funified\u002Fconnection",[446,466,467],{"class":456}," \\\n",[446,469,471,474,477,481,484],{"class":448,"line":470},2,[446,472,473],{"class":456},"  -H",[446,475,476],{"class":460}," \"Authorization: Bearer ",[446,478,480],{"class":479},"sAvwS","$UNIFIED_API_KEY",[446,482,483],{"class":460},"\"",[446,485,467],{"class":456},[446,487,489,491,494],{"class":448,"line":488},3,[446,490,473],{"class":456},[446,492,493],{"class":460}," \"Content-Type: application\u002Fjson\"",[446,495,467],{"class":456},[446,497,499,502],{"class":448,"line":498},4,[446,500,501],{"class":456},"  -d",[446,503,504],{"class":460}," '{\n",[446,506,508],{"class":448,"line":507},5,[446,509,510],{"class":460},"    \"integration_type\": \"hubspot\",\n",[446,512,514],{"class":448,"line":513},6,[446,515,516],{"class":460},"    \"categories\": [\"crm\"],\n",[446,518,520],{"class":448,"line":519},7,[446,521,522],{"class":460},"    \"permissions\": [\"crm_contact_read\", \"crm_contact_write\"],\n",[446,524,526],{"class":448,"line":525},8,[446,527,528],{"class":460},"    \"external_xref\": \"customer_123\",\n",[446,530,532],{"class":448,"line":531},9,[446,533,534],{"class":460},"    \"auth\": {\n",[446,536,538],{"class":448,"line":537},10,[446,539,540],{"class":460},"      \"access_token\": \"…\",\n",[446,542,544],{"class":448,"line":543},11,[446,545,546],{"class":460},"      \"refresh_token\": \"…\",\n",[446,548,550],{"class":448,"line":549},12,[446,551,552],{"class":460},"      \"expiry_date\": \"2026-10-01T00:00:00Z\"\n",[446,554,556],{"class":448,"line":555},13,[446,557,558],{"class":460},"    }\n",[446,560,562],{"class":448,"line":561},14,[446,563,564],{"class":460},"  }'\n",[15,566,567,568,571],{},"The response contains the new connection's ",[134,569,570],{},"id",". Store it next to your customer record, where you currently keep the other provider's account token or ID.",[340,573,575],{"id":574},"_4-swap-your-api-calls","4. Swap your API calls",[15,577,578,579,582,583,587],{},"Replace each call with its Unified.to equivalent. The URL pattern is ",[134,580,581],{},"https:\u002F\u002Fapi.unified.to\u002F{category}\u002F{connection_id}\u002F{object}",", so a single client covers every integration in a category. Our ",[30,584,586],{"href":585},"\u002Freference\u002Fsdks","SDKs"," wrap the same endpoints if you prefer typed clients.",[15,589,590,591,595,596,385],{},"Update your field mapping from the other provider's model to the Unified.to model for each object; the ",[30,592,594],{"href":593},"\u002Funified\u002Foverview","API Reference"," lists every field. Where you read vendor-specific fields, use ",[134,597,228],{},[340,599,601],{"id":600},"_5-replace-sync-and-webhooks","5. Replace sync and webhooks",[15,603,604,605,608,609,198,612,615,616,619,620,624,625,628],{},"Create a ",[30,606,607],{"href":268},"webhook"," for each connection and object you want to track, using ",[134,610,611],{},"created",[134,613,614],{},"updated"," or ",[134,617,618],{},"deleted"," events. Integrations without native webhooks get ",[30,621,623],{"href":622},"\u002Fconcepts\u002Fvirtual_webhooks","virtual webhooks",", which check for changes on the interval you set. Webhooks can backfill historical data, so they can also replace an initial sync. Verify each payload's ",[134,626,627],{},"sig256"," signature.",[340,630,632],{"id":631},"_6-run-both-then-cut-over","6. Run both, then cut over",[15,634,635],{},"Run Unified.to alongside your current provider for a subset of customers and compare results. Once you're confident, switch your feature flag, move the remaining customers, and delete the connections on your old provider so it stops holding their data.",[77,637,639],{"id":638},"checklist","Checklist",[301,641,644,654,660,669,675,681,690,696],{"className":642},[643],"contains-task-list",[304,645,648,653],{"className":646},[647],"task-list-item",[649,650],"input",{"disabled":651,"type":652},true,"checkbox"," Every object, field and write operation you use is supported for your integrations",[304,655,657,659],{"className":656},[647],[649,658],{"disabled":651,"type":652}," Integrations activated in Production with your own OAuth credentials and the right scopes",[304,661,663,665,666,668],{"className":662},[647],[649,664],{"disabled":651,"type":652}," Authorization component (or auth URL) live, with ",[134,667,419],{}," set to your customer ID",[304,670,672,674],{"className":671},[647],[649,673],{"disabled":651,"type":652}," Existing connections re-authorized or imported, and connection IDs stored",[304,676,678,680],{"className":677},[647],[649,679],{"disabled":651,"type":652}," API calls, pagination and filters translated",[304,682,684,686,687,689],{"className":683},[647],[649,685],{"disabled":651,"type":652}," Field mapping updated, including any ",[134,688,228],{}," fields",[304,691,693,695],{"className":692},[647],[649,694],{"disabled":651,"type":652}," Webhooks created, signatures verified, and old sync jobs retired",[304,697,699,701],{"className":698},[647],[649,700],{"disabled":651,"type":652}," Old provider's connections deleted after cut-over",[15,703,704,705,710,711,385],{},"Questions along the way? Join our ",[30,706,709],{"href":707,"rel":708},"https:\u002F\u002Fdiscord.gg\u002F2nsAPmbx",[73],"Discord"," or email ",[30,712,714],{"href":713},"mailto:hello@unified.to","hello@unified.to",[716,717,718],"style",{},"html pre.shiki code .s5n6i, html code.shiki .s5n6i{--shiki-default:#B392F0;--shiki-dark:#B392F0;--shiki-light:#6F42C1}html pre.shiki code .sXWYR, html code.shiki .sXWYR{--shiki-default:#79B8FF;--shiki-dark:#79B8FF;--shiki-light:#005CC5}html pre.shiki code .s4Y1p, html code.shiki .s4Y1p{--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF;--shiki-light:#032F62}html pre.shiki code .sAvwS, html code.shiki .sAvwS{--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8;--shiki-light:#24292E}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":442,"searchDepth":470,"depth":470,"links":720},[721,722,723,731],{"id":79,"depth":470,"text":80},{"id":288,"depth":470,"text":289},{"id":337,"depth":470,"text":338,"children":724},[725,726,727,728,729,730],{"id":342,"depth":488,"text":343},{"id":363,"depth":488,"text":364},{"id":403,"depth":488,"text":404},{"id":574,"depth":488,"text":575},{"id":600,"depth":488,"text":601},{"id":631,"depth":488,"text":632},{"id":638,"depth":470,"text":639},"Move your integrations from Merge, Apideck, Kombo, Finch, Rutter or another unified API to Unified.to.","md",{},"\u002Fmigrate\u002Foverview",{"title":6,"description":732},"migrate\u002Foverview","MIWsdHzryrRmBx-0qqfU_3LI132FhqHCRVQSbvIDKD0",1790974222279]