[{"data":1,"prerenderedAt":1838},["ShallowReactive",2],{"navigation":3,"\u002Fsync-api\u002Fquickstart":99,"\u002Fsync-api\u002Fquickstart-surround":1831},[4,16,52,71,91],{"title":5,"path":6,"stem":7,"children":8,"icon":15},"Getting Started","\u002Fgetting-started","1.getting-started\u002F1.index",[9,11],{"title":10,"path":6,"stem":7},"Introduction",{"title":12,"path":13,"stem":14},"Authentication","\u002Fgetting-started\u002Fauthentication","1.getting-started\u002F2.authentication","i-lucide-rocket",{"title":17,"path":18,"stem":19,"children":20,"icon":51},"GraphQL API","\u002Fgraphql-api","2.graphql-api\u002F1.index",[21,23,27,31,35,39,43,47],{"title":22,"path":18,"stem":19},"API Overview",{"title":24,"path":25,"stem":26},"Querying Patterns","\u002Fgraphql-api\u002Fquerying","2.graphql-api\u002F2.querying",{"title":28,"path":29,"stem":30},"Mutation Patterns","\u002Fgraphql-api\u002Fmutations","2.graphql-api\u002F3.mutations",{"title":32,"path":33,"stem":34},"List SaaS Applications","\u002Fgraphql-api\u002Fguides\u002Flist-applications","2.graphql-api\u002F4.guides\u002F1.list-applications",{"title":36,"path":37,"stem":38},"Find Unused Licenses","\u002Fgraphql-api\u002Fguides\u002Ffind-unused-licenses","2.graphql-api\u002F4.guides\u002F2.find-unused-licenses",{"title":40,"path":41,"stem":42},"Retrieve Upcoming Renewals","\u002Fgraphql-api\u002Fguides\u002Fupcoming-renewals","2.graphql-api\u002F4.guides\u002F3.upcoming-renewals",{"title":44,"path":45,"stem":46},"Handle GraphQL Errors","\u002Fgraphql-api\u002Fguides\u002Fhandle-errors","2.graphql-api\u002F4.guides\u002F4.handle-errors",{"title":48,"path":49,"icon":50},"API Reference","\u002Fgql-schema-reference","i-lucide-file-code","i-lucide-braces",{"title":53,"path":54,"stem":55,"children":56,"icon":70},"Sync API","\u002Fsync-api","3.sync-api\u002F1.index",[57,59,63,67],{"title":58,"path":54,"stem":55},"Viio Sync API",{"title":60,"path":61,"stem":62},"Quickstart","\u002Fsync-api\u002Fquickstart","3.sync-api\u002F2.quickstart",{"title":64,"path":65,"icon":66},"Examples","\u002Fsync-api\u002Faws-lambda-python","i-lucide-code-xml",{"title":68,"path":69,"icon":50},"SDK Reference","\u002Fsync-api\u002Fapi-reference","i-lucide-refresh-cw",{"title":72,"path":73,"stem":74,"children":75,"icon":90},"MCP Server","\u002Fmcp-server","4.mcp-server\u002F1.index",[76,78,82,86],{"title":77,"path":73,"stem":74},"Viio MCP Server",{"title":79,"path":80,"stem":81},"Setup","\u002Fmcp-server\u002Fsetup","4.mcp-server\u002F2.setup",{"title":83,"path":84,"stem":85},"Available Tools","\u002Fmcp-server\u002Ftools","4.mcp-server\u002F3.tools",{"title":87,"path":88,"stem":89},"SaaS Analysis Use Cases","\u002Fmcp-server\u002Fuse-cases","4.mcp-server\u002F4.use-cases","i-lucide-bot",{"title":92,"path":93,"stem":94,"children":95,"icon":98},"AI Integration","\u002Fai","5.ai\u002F1.index",[96],{"title":97,"path":93,"stem":94},"llms.txt","i-lucide-sparkles",{"id":100,"title":60,"body":101,"dateModified":1821,"datePublished":1822,"description":1823,"extension":1824,"links":1825,"meta":1826,"navigation":339,"path":61,"seo":1827,"stem":62,"__hash__":1830},"docs\u002F3.sync-api\u002F2.quickstart.md",{"type":102,"value":103,"toc":1807},"minimark",[104,108,111,116,119,140,147,150,221,225,277,281,705,715,719,722,931,934,938,941,1253,1262,1265,1268,1276,1279,1286,1291,1294,1383,1389,1393,1396,1443,1446,1485,1492,1496,1499,1544,1547,1551,1554,1719,1722,1742,1745,1748,1752,1755,1759,1796,1799,1803],[105,106,107],"p",{},"A Sync API batch groups all records from one extraction run. Only one batch can be active for a direct integration installation at a time.",[105,109,110],{},"The official SDKs manage the authenticated gRPC channel, attach the active batch ID to writes, and prevent local operations after the batch is completed or aborted.",[112,113,115],"h2",{"id":114},"before-you-start","Before You Start",[105,117,118],{},"You need:",[120,121,122,126,129,137],"ul",{},[123,124,125],"li",{},"A passive direct integration installation under which the source's data can be reported.",[123,127,128],{},"The direct integration installation ID.",[123,130,131,132,136],{},"A Viio API key with the ",[133,134,135],"code",{},"integration:sync"," permission.",[123,138,139],{},"An official Sync API SDK.",[141,142,144],"callout",{"icon":143},"i-lucide-info",[105,145,146],{},"Currently, Viio must provision the passive integration installation for you. After it is provisioned, open the integration details view in Viio to copy its direct integration installation ID.",[105,148,149],{},"Install an official SDK:",[151,152,154,193],"tabs",{"sync":153},"sync-api-language",[155,156,158],"tabs-item",{"label":157},"C#",[159,160,165],"pre",{"className":161,"code":162,"language":163,"meta":164,"style":164},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","dotnet add package Viio.SyncApi.Sdk --version 1.1.0\n","bash","",[133,166,167],{"__ignoreMap":164},[168,169,172,176,180,183,186,189],"span",{"class":170,"line":171},"line",1,[168,173,175],{"class":174},"sBMFI","dotnet",[168,177,179],{"class":178},"sfazB"," add",[168,181,182],{"class":178}," package",[168,184,185],{"class":178}," Viio.SyncApi.Sdk",[168,187,188],{"class":178}," --version",[168,190,192],{"class":191},"sbssI"," 1.1.0\n",[155,194,196],{"label":195},"Python",[159,197,199],{"className":161,"code":198,"language":163,"meta":164,"style":164},"python -m pip install viio-sync-api-sdk==0.2.0\n",[133,200,201],{"__ignoreMap":164},[168,202,203,206,209,212,215,218],{"class":170,"line":171},[168,204,205],{"class":174},"python",[168,207,208],{"class":178}," -m",[168,210,211],{"class":178}," pip",[168,213,214],{"class":178}," install",[168,216,217],{"class":178}," viio-sync-api-sdk==",[168,219,220],{"class":191},"0.2.0\n",[112,222,224],{"id":223},"sdk-lifecycle","SDK Lifecycle",[226,227,228,241],"table",{},[229,230,231],"thead",{},[232,233,234,238],"tr",{},[235,236,237],"th",{},"Step",[235,239,240],{},"Purpose",[242,243,244,253,261,269],"tbody",{},[232,245,246,250],{},[247,248,249],"td",{},"Start",[247,251,252],{},"Acquire the integration lock and create a batch",[232,254,255,258],{},[247,256,257],{},"Write",[247,259,260],{},"Send one typed collection or chunk for the batch",[232,262,263,266],{},[247,264,265],{},"Complete",[247,267,268],{},"Reconcile snapshot-backed data and release the lock",[232,270,271,274],{},[247,272,273],{},"Abort",[247,275,276],{},"Stop the run and release the lock without completing snapshots",[112,278,280],{"id":279},"configure-the-client","Configure the Client",[151,282,283,516],{"sync":153},[155,284,285],{"label":157},[159,286,290],{"className":287,"code":288,"language":289,"meta":164,"style":164},"language-csharp shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","using Viio.SyncApi;\nusing Viio.SyncApi.V1.Contracts;\n\nvar apiKey = Environment.GetEnvironmentVariable(\"VIIO_API_KEY\")\n    ?? throw new InvalidOperationException(\"VIIO_API_KEY is required.\");\n\nusing var client = new SyncApiClient(\n    new SyncApiClientOptions(\n        new Uri(\"https:\u002F\u002Fsync.viio.io\"),\n        SyncApiAuthentication.ApiKey(apiKey)\n    )\n);\n\nvar cancellationToken = CancellationToken.None;\n","csharp",[133,291,292,311,334,341,376,404,409,430,441,462,480,486,491,496],{"__ignoreMap":164},[168,293,294,297,301,305,308],{"class":170,"line":171},[168,295,296],{"class":191},"using",[168,298,300],{"class":299},"sTEyZ"," Viio",[168,302,304],{"class":303},"sMK4o",".",[168,306,307],{"class":299},"SyncApi",[168,309,310],{"class":303},";\n",[168,312,314,316,318,320,322,324,327,329,332],{"class":170,"line":313},2,[168,315,296],{"class":191},[168,317,300],{"class":299},[168,319,304],{"class":303},[168,321,307],{"class":299},[168,323,304],{"class":303},[168,325,326],{"class":299},"V1",[168,328,304],{"class":303},[168,330,331],{"class":299},"Contracts",[168,333,310],{"class":303},[168,335,337],{"class":170,"line":336},3,[168,338,340],{"emptyLinePlaceholder":339},true,"\n",[168,342,344,347,350,353,356,358,362,365,368,371,373],{"class":170,"line":343},4,[168,345,346],{"class":174},"var",[168,348,349],{"class":174}," apiKey",[168,351,352],{"class":303}," =",[168,354,355],{"class":299}," Environment",[168,357,304],{"class":303},[168,359,361],{"class":360},"s2Zo4","GetEnvironmentVariable",[168,363,364],{"class":303},"(",[168,366,367],{"class":303},"\"",[168,369,370],{"class":178},"VIIO_API_KEY",[168,372,367],{"class":303},[168,374,375],{"class":303},")\n",[168,377,379,382,386,389,392,394,396,399,401],{"class":170,"line":378},5,[168,380,381],{"class":303},"    ??",[168,383,385],{"class":384},"s7zQu"," throw",[168,387,388],{"class":303}," new",[168,390,391],{"class":174}," InvalidOperationException",[168,393,364],{"class":303},[168,395,367],{"class":303},[168,397,398],{"class":178},"VIIO_API_KEY is required.",[168,400,367],{"class":303},[168,402,403],{"class":303},");\n",[168,405,407],{"class":170,"line":406},6,[168,408,340],{"emptyLinePlaceholder":339},[168,410,412,414,417,420,422,424,427],{"class":170,"line":411},7,[168,413,296],{"class":384},[168,415,416],{"class":174}," var",[168,418,419],{"class":174}," client",[168,421,352],{"class":303},[168,423,388],{"class":303},[168,425,426],{"class":174}," SyncApiClient",[168,428,429],{"class":303},"(\n",[168,431,433,436,439],{"class":170,"line":432},8,[168,434,435],{"class":303},"    new",[168,437,438],{"class":174}," SyncApiClientOptions",[168,440,429],{"class":303},[168,442,444,447,450,452,454,457,459],{"class":170,"line":443},9,[168,445,446],{"class":303},"        new",[168,448,449],{"class":174}," Uri",[168,451,364],{"class":303},[168,453,367],{"class":303},[168,455,456],{"class":178},"https:\u002F\u002Fsync.viio.io",[168,458,367],{"class":303},[168,460,461],{"class":303},"),\n",[168,463,465,468,470,473,475,478],{"class":170,"line":464},10,[168,466,467],{"class":299},"        SyncApiAuthentication",[168,469,304],{"class":303},[168,471,472],{"class":360},"ApiKey",[168,474,364],{"class":303},[168,476,477],{"class":299},"apiKey",[168,479,375],{"class":303},[168,481,483],{"class":170,"line":482},11,[168,484,485],{"class":303},"    )\n",[168,487,489],{"class":170,"line":488},12,[168,490,403],{"class":303},[168,492,494],{"class":170,"line":493},13,[168,495,340],{"emptyLinePlaceholder":339},[168,497,499,501,504,506,509,511,514],{"class":170,"line":498},14,[168,500,346],{"class":174},[168,502,503],{"class":174}," cancellationToken",[168,505,352],{"class":303},[168,507,508],{"class":299}," CancellationToken",[168,510,304],{"class":303},[168,512,513],{"class":299},"None",[168,515,310],{"class":303},[155,517,518],{"label":195},[159,519,522],{"className":520,"code":521,"language":205,"meta":164,"style":164},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import os\n\nfrom viio_sync_api import SyncApiAuthentication, SyncApiClient, SyncApiClientOptions\nfrom viio_sync_api.v1 import Account, AccountRecords, GenericAccountDetails, SyncRecordsRequest\n\n\noptions = SyncApiClientOptions(\n    endpoint=\"https:\u002F\u002Fsync.viio.io\",\n    authentication=SyncApiAuthentication.api_key(os.environ[\"VIIO_API_KEY\"]),\n)\n\nasync with SyncApiClient(options) as client:\n    ...\n",[133,523,524,532,536,559,591,595,599,611,628,666,670,674,700],{"__ignoreMap":164},[168,525,526,529],{"class":170,"line":171},[168,527,528],{"class":384},"import",[168,530,531],{"class":299}," os\n",[168,533,534],{"class":170,"line":313},[168,535,340],{"emptyLinePlaceholder":339},[168,537,538,541,544,546,549,552,554,556],{"class":170,"line":336},[168,539,540],{"class":384},"from",[168,542,543],{"class":299}," viio_sync_api ",[168,545,528],{"class":384},[168,547,548],{"class":299}," SyncApiAuthentication",[168,550,551],{"class":303},",",[168,553,426],{"class":299},[168,555,551],{"class":303},[168,557,558],{"class":299}," SyncApiClientOptions\n",[168,560,561,563,566,568,571,573,576,578,581,583,586,588],{"class":170,"line":343},[168,562,540],{"class":384},[168,564,565],{"class":299}," viio_sync_api",[168,567,304],{"class":303},[168,569,570],{"class":299},"v1 ",[168,572,528],{"class":384},[168,574,575],{"class":299}," Account",[168,577,551],{"class":303},[168,579,580],{"class":299}," AccountRecords",[168,582,551],{"class":303},[168,584,585],{"class":299}," GenericAccountDetails",[168,587,551],{"class":303},[168,589,590],{"class":299}," SyncRecordsRequest\n",[168,592,593],{"class":170,"line":378},[168,594,340],{"emptyLinePlaceholder":339},[168,596,597],{"class":170,"line":406},[168,598,340],{"emptyLinePlaceholder":339},[168,600,601,604,607,609],{"class":170,"line":411},[168,602,603],{"class":299},"options ",[168,605,606],{"class":303},"=",[168,608,438],{"class":360},[168,610,429],{"class":303},[168,612,613,617,619,621,623,625],{"class":170,"line":432},[168,614,616],{"class":615},"sHdIc","    endpoint",[168,618,606],{"class":303},[168,620,367],{"class":303},[168,622,456],{"class":178},[168,624,367],{"class":303},[168,626,627],{"class":303},",\n",[168,629,630,633,635,638,640,643,645,648,650,654,657,659,661,663],{"class":170,"line":443},[168,631,632],{"class":615},"    authentication",[168,634,606],{"class":303},[168,636,637],{"class":360},"SyncApiAuthentication",[168,639,304],{"class":303},[168,641,642],{"class":360},"api_key",[168,644,364],{"class":303},[168,646,647],{"class":360},"os",[168,649,304],{"class":303},[168,651,653],{"class":652},"swJcz","environ",[168,655,656],{"class":303},"[",[168,658,367],{"class":303},[168,660,370],{"class":178},[168,662,367],{"class":303},[168,664,665],{"class":303},"]),\n",[168,667,668],{"class":170,"line":464},[168,669,375],{"class":303},[168,671,672],{"class":170,"line":482},[168,673,340],{"emptyLinePlaceholder":339},[168,675,676,679,682,684,686,689,692,695,697],{"class":170,"line":488},[168,677,678],{"class":384},"async",[168,680,681],{"class":384}," with",[168,683,426],{"class":360},[168,685,364],{"class":303},[168,687,688],{"class":360},"options",[168,690,691],{"class":303},")",[168,693,694],{"class":384}," as",[168,696,419],{"class":299},[168,698,699],{"class":303},":\n",[168,701,702],{"class":170,"line":493},[168,703,704],{"class":299},"    ...\n",[105,706,707,708,710,711,714],{},"The API key must have the ",[133,709,135],{}," permission. The SDK sends it using the ",[133,712,713],{},"Authorization: ApiKey YOUR_API_KEY"," gRPC metadata value.",[112,716,718],{"id":717},"startsyncbatch","StartSyncBatch",[105,720,721],{},"Start a batch for the direct integration installation receiving the data.",[151,723,724,862],{"sync":153},[155,725,726],{"label":157},[159,727,729],{"className":287,"code":728,"language":289,"meta":164,"style":164},"var directIntegrationInstallationId =\n    Environment.GetEnvironmentVariable(\n        \"VIIO_DIRECT_INTEGRATION_INSTALLATION_ID\"\n    )\n    ?? throw new InvalidOperationException(\n        \"VIIO_DIRECT_INTEGRATION_INSTALLATION_ID is required.\"\n    );\n\nusing var batch = await client.StartBatch(\n    directIntegrationInstallationId,\n    cancellationToken\n);\n\nConsole.WriteLine(batch.BatchId);\n",[133,730,731,741,752,763,767,779,788,793,797,820,827,832,836,840],{"__ignoreMap":164},[168,732,733,735,738],{"class":170,"line":171},[168,734,346],{"class":174},[168,736,737],{"class":174}," directIntegrationInstallationId",[168,739,740],{"class":303}," =\n",[168,742,743,746,748,750],{"class":170,"line":313},[168,744,745],{"class":299},"    Environment",[168,747,304],{"class":303},[168,749,361],{"class":360},[168,751,429],{"class":303},[168,753,754,757,760],{"class":170,"line":336},[168,755,756],{"class":303},"        \"",[168,758,759],{"class":178},"VIIO_DIRECT_INTEGRATION_INSTALLATION_ID",[168,761,762],{"class":303},"\"\n",[168,764,765],{"class":170,"line":343},[168,766,485],{"class":303},[168,768,769,771,773,775,777],{"class":170,"line":378},[168,770,381],{"class":303},[168,772,385],{"class":384},[168,774,388],{"class":303},[168,776,391],{"class":174},[168,778,429],{"class":303},[168,780,781,783,786],{"class":170,"line":406},[168,782,756],{"class":303},[168,784,785],{"class":178},"VIIO_DIRECT_INTEGRATION_INSTALLATION_ID is required.",[168,787,762],{"class":303},[168,789,790],{"class":170,"line":411},[168,791,792],{"class":303},"    );\n",[168,794,795],{"class":170,"line":432},[168,796,340],{"emptyLinePlaceholder":339},[168,798,799,801,803,806,808,811,813,815,818],{"class":170,"line":443},[168,800,296],{"class":384},[168,802,416],{"class":174},[168,804,805],{"class":174}," batch",[168,807,352],{"class":303},[168,809,810],{"class":303}," await",[168,812,419],{"class":299},[168,814,304],{"class":303},[168,816,817],{"class":360},"StartBatch",[168,819,429],{"class":303},[168,821,822,825],{"class":170,"line":464},[168,823,824],{"class":299},"    directIntegrationInstallationId",[168,826,627],{"class":303},[168,828,829],{"class":170,"line":482},[168,830,831],{"class":299},"    cancellationToken\n",[168,833,834],{"class":170,"line":488},[168,835,403],{"class":303},[168,837,838],{"class":170,"line":493},[168,839,340],{"emptyLinePlaceholder":339},[168,841,842,845,847,850,852,855,857,860],{"class":170,"line":498},[168,843,844],{"class":299},"Console",[168,846,304],{"class":303},[168,848,849],{"class":360},"WriteLine",[168,851,364],{"class":303},[168,853,854],{"class":299},"batch",[168,856,304],{"class":303},[168,858,859],{"class":299},"BatchId",[168,861,403],{"class":303},[155,863,864],{"label":195},[159,865,867],{"className":520,"code":866,"language":205,"meta":164,"style":164},"batch = await client.start_batch(\n    os.environ[\"VIIO_DIRECT_INTEGRATION_INSTALLATION_ID\"]\n)\n\nprint(batch.batch_id)\n",[133,868,869,887,907,911,915],{"__ignoreMap":164},[168,870,871,874,876,878,880,882,885],{"class":170,"line":171},[168,872,873],{"class":299},"batch ",[168,875,606],{"class":303},[168,877,810],{"class":384},[168,879,419],{"class":299},[168,881,304],{"class":303},[168,883,884],{"class":360},"start_batch",[168,886,429],{"class":303},[168,888,889,892,894,896,898,900,902,904],{"class":170,"line":313},[168,890,891],{"class":360},"    os",[168,893,304],{"class":303},[168,895,653],{"class":652},[168,897,656],{"class":303},[168,899,367],{"class":303},[168,901,759],{"class":178},[168,903,367],{"class":303},[168,905,906],{"class":303},"]\n",[168,908,909],{"class":170,"line":336},[168,910,375],{"class":303},[168,912,913],{"class":170,"line":343},[168,914,340],{"emptyLinePlaceholder":339},[168,916,917,920,922,924,926,929],{"class":170,"line":378},[168,918,919],{"class":360},"print",[168,921,364],{"class":303},[168,923,854],{"class":360},[168,925,304],{"class":303},[168,927,928],{"class":652},"batch_id",[168,930,375],{"class":303},[105,932,933],{},"The SDK keeps the returned batch ID on the batch object and adds it to subsequent writes. If another run owns the integration lock, the SDK raises a batch-already-in-progress error.",[112,935,937],{"id":936},"syncrecords","SyncRecords",[105,939,940],{},"Create a typed records wrapper and send it through the active batch.",[151,942,943,1121],{"sync":153},[155,944,945],{"label":157},[159,946,948],{"className":287,"code":947,"language":289,"meta":164,"style":164},"var accounts = new AccountRecords();\naccounts.Records.Add(\n    new Account\n    {\n        Generic = new GenericAccountDetails\n        {\n            Id = \"account-100\",\n            Email = \"owner@example.com\",\n            Active = true,\n        },\n    }\n);\n\nawait batch.Write(\n    new SyncRecordsRequest { Accounts = accounts },\n    cancellationToken\n);\n",[133,949,950,966,983,990,995,1007,1012,1029,1045,1058,1063,1068,1072,1076,1089,1111,1116],{"__ignoreMap":164},[168,951,952,954,957,959,961,963],{"class":170,"line":171},[168,953,346],{"class":174},[168,955,956],{"class":174}," accounts",[168,958,352],{"class":303},[168,960,388],{"class":303},[168,962,580],{"class":174},[168,964,965],{"class":303},"();\n",[168,967,968,971,973,976,978,981],{"class":170,"line":313},[168,969,970],{"class":299},"accounts",[168,972,304],{"class":303},[168,974,975],{"class":299},"Records",[168,977,304],{"class":303},[168,979,980],{"class":360},"Add",[168,982,429],{"class":303},[168,984,985,987],{"class":170,"line":336},[168,986,435],{"class":303},[168,988,989],{"class":174}," Account\n",[168,991,992],{"class":170,"line":343},[168,993,994],{"class":303},"    {\n",[168,996,997,1000,1002,1004],{"class":170,"line":378},[168,998,999],{"class":299},"        Generic ",[168,1001,606],{"class":303},[168,1003,388],{"class":303},[168,1005,1006],{"class":174}," GenericAccountDetails\n",[168,1008,1009],{"class":170,"line":406},[168,1010,1011],{"class":303},"        {\n",[168,1013,1014,1017,1019,1022,1025,1027],{"class":170,"line":411},[168,1015,1016],{"class":299},"            Id ",[168,1018,606],{"class":303},[168,1020,1021],{"class":303}," \"",[168,1023,1024],{"class":178},"account-100",[168,1026,367],{"class":303},[168,1028,627],{"class":303},[168,1030,1031,1034,1036,1038,1041,1043],{"class":170,"line":432},[168,1032,1033],{"class":299},"            Email ",[168,1035,606],{"class":303},[168,1037,1021],{"class":303},[168,1039,1040],{"class":178},"owner@example.com",[168,1042,367],{"class":303},[168,1044,627],{"class":303},[168,1046,1047,1050,1052,1056],{"class":170,"line":443},[168,1048,1049],{"class":299},"            Active ",[168,1051,606],{"class":303},[168,1053,1055],{"class":1054},"sfNiH"," true",[168,1057,627],{"class":303},[168,1059,1060],{"class":170,"line":464},[168,1061,1062],{"class":303},"        },\n",[168,1064,1065],{"class":170,"line":482},[168,1066,1067],{"class":303},"    }\n",[168,1069,1070],{"class":170,"line":488},[168,1071,403],{"class":303},[168,1073,1074],{"class":170,"line":493},[168,1075,340],{"emptyLinePlaceholder":339},[168,1077,1078,1081,1083,1085,1087],{"class":170,"line":498},[168,1079,1080],{"class":303},"await",[168,1082,805],{"class":299},[168,1084,304],{"class":303},[168,1086,257],{"class":360},[168,1088,429],{"class":303},[168,1090,1092,1094,1097,1100,1103,1105,1108],{"class":170,"line":1091},15,[168,1093,435],{"class":303},[168,1095,1096],{"class":174}," SyncRecordsRequest",[168,1098,1099],{"class":303}," {",[168,1101,1102],{"class":299}," Accounts ",[168,1104,606],{"class":303},[168,1106,1107],{"class":299}," accounts ",[168,1109,1110],{"class":303},"},\n",[168,1112,1114],{"class":170,"line":1113},16,[168,1115,831],{"class":299},[168,1117,1119],{"class":170,"line":1118},17,[168,1120,403],{"class":303},[155,1122,1123],{"label":195},[159,1124,1126],{"className":520,"code":1125,"language":205,"meta":164,"style":164},"await batch.write(\n    SyncRecordsRequest(\n        accounts=AccountRecords(\n            records=[\n                Account(\n                    generic=GenericAccountDetails(\n                        id=\"account-100\",\n                        email=\"owner@example.com\",\n                        active=True,\n                    )\n                )\n            ]\n        )\n    )\n)\n",[133,1127,1128,1141,1148,1160,1168,1175,1187,1202,1217,1225,1230,1235,1240,1245,1249],{"__ignoreMap":164},[168,1129,1130,1132,1134,1136,1139],{"class":170,"line":171},[168,1131,1080],{"class":384},[168,1133,805],{"class":299},[168,1135,304],{"class":303},[168,1137,1138],{"class":360},"write",[168,1140,429],{"class":303},[168,1142,1143,1146],{"class":170,"line":313},[168,1144,1145],{"class":360},"    SyncRecordsRequest",[168,1147,429],{"class":303},[168,1149,1150,1153,1155,1158],{"class":170,"line":336},[168,1151,1152],{"class":615},"        accounts",[168,1154,606],{"class":303},[168,1156,1157],{"class":360},"AccountRecords",[168,1159,429],{"class":303},[168,1161,1162,1165],{"class":170,"line":343},[168,1163,1164],{"class":615},"            records",[168,1166,1167],{"class":303},"=[\n",[168,1169,1170,1173],{"class":170,"line":378},[168,1171,1172],{"class":360},"                Account",[168,1174,429],{"class":303},[168,1176,1177,1180,1182,1185],{"class":170,"line":406},[168,1178,1179],{"class":615},"                    generic",[168,1181,606],{"class":303},[168,1183,1184],{"class":360},"GenericAccountDetails",[168,1186,429],{"class":303},[168,1188,1189,1192,1194,1196,1198,1200],{"class":170,"line":411},[168,1190,1191],{"class":615},"                        id",[168,1193,606],{"class":303},[168,1195,367],{"class":303},[168,1197,1024],{"class":178},[168,1199,367],{"class":303},[168,1201,627],{"class":303},[168,1203,1204,1207,1209,1211,1213,1215],{"class":170,"line":432},[168,1205,1206],{"class":615},"                        email",[168,1208,606],{"class":303},[168,1210,367],{"class":303},[168,1212,1040],{"class":178},[168,1214,367],{"class":303},[168,1216,627],{"class":303},[168,1218,1219,1222],{"class":170,"line":443},[168,1220,1221],{"class":615},"                        active",[168,1223,1224],{"class":303},"=True,\n",[168,1226,1227],{"class":170,"line":464},[168,1228,1229],{"class":303},"                    )\n",[168,1231,1232],{"class":170,"line":482},[168,1233,1234],{"class":303},"                )\n",[168,1236,1237],{"class":170,"line":488},[168,1238,1239],{"class":303},"            ]\n",[168,1241,1242],{"class":170,"line":493},[168,1243,1244],{"class":303},"        )\n",[168,1246,1247],{"class":170,"line":498},[168,1248,485],{"class":303},[168,1250,1251],{"class":170,"line":1091},[168,1252,375],{"class":303},[105,1254,1255,1256,1261],{},"The collection and record model must describe the same data type, and each record selects one supported details model. See the ",[1257,1258,1260],"a",{"href":1259},"\u002Fsync-api\u002Fapi-reference\u002Fmodels","Model Reference"," for every collection, record model, and property.",[105,1263,1264],{},"The SDK adds the active batch identifier automatically and requires exactly one typed collection in each write request. Use repeated writes for additional data types or chunks.",[105,1266,1267],{},"You may:",[120,1269,1270,1273],{},[123,1271,1272],{},"Split a large typed collection across several writes.",[123,1274,1275],{},"Send data types in any order across writes.",[105,1277,1278],{},"Writes for one batch must be sequential. Wait for the current write to finish before starting the next one, and finish every write before completing the batch.",[105,1280,1281,1282,1285],{},"Each ",[133,1283,1284],{},"SyncRecordsRequest"," message must be smaller than 16 MiB. Use stable source IDs so later batches update the same logical records.",[1287,1288,1290],"h3",{"id":1289},"empty-snapshots","Empty snapshots",[105,1292,1293],{},"A present typed collection with an empty record list means that the source was processed successfully and currently contains no records of that type.",[151,1295,1296,1345],{"sync":153},[155,1297,1298],{"label":157},[159,1299,1301],{"className":287,"code":1300,"language":289,"meta":164,"style":164},"await batch.Write(\n    new SyncRecordsRequest { Accounts = new AccountRecords() },\n    cancellationToken\n);\n",[133,1302,1303,1315,1337,1341],{"__ignoreMap":164},[168,1304,1305,1307,1309,1311,1313],{"class":170,"line":171},[168,1306,1080],{"class":303},[168,1308,805],{"class":299},[168,1310,304],{"class":303},[168,1312,257],{"class":360},[168,1314,429],{"class":303},[168,1316,1317,1319,1321,1323,1325,1327,1329,1331,1334],{"class":170,"line":313},[168,1318,435],{"class":303},[168,1320,1096],{"class":174},[168,1322,1099],{"class":303},[168,1324,1102],{"class":299},[168,1326,606],{"class":303},[168,1328,388],{"class":303},[168,1330,580],{"class":174},[168,1332,1333],{"class":303},"()",[168,1335,1336],{"class":303}," },\n",[168,1338,1339],{"class":170,"line":336},[168,1340,831],{"class":299},[168,1342,1343],{"class":170,"line":343},[168,1344,403],{"class":303},[155,1346,1347],{"label":195},[159,1348,1350],{"className":520,"code":1349,"language":205,"meta":164,"style":164},"await batch.write(\n    SyncRecordsRequest(accounts=AccountRecords())\n)\n",[133,1351,1352,1364,1379],{"__ignoreMap":164},[168,1353,1354,1356,1358,1360,1362],{"class":170,"line":171},[168,1355,1080],{"class":384},[168,1357,805],{"class":299},[168,1359,304],{"class":303},[168,1361,1138],{"class":360},[168,1363,429],{"class":303},[168,1365,1366,1368,1370,1372,1374,1376],{"class":170,"line":313},[168,1367,1145],{"class":360},[168,1369,364],{"class":303},[168,1371,970],{"class":615},[168,1373,606],{"class":303},[168,1375,1157],{"class":360},[168,1377,1378],{"class":303},"())\n",[168,1380,1381],{"class":170,"line":336},[168,1382,375],{"class":303},[105,1384,1385,1386,1388],{},"When the batch completes, Viio reconciles that empty account snapshot and marks accounts from the previous snapshot as removed. Omitting ",[133,1387,970],{}," means accounts were not processed in that message; omission alone does not register an empty snapshot.",[112,1390,1392],{"id":1391},"completesyncbatch","CompleteSyncBatch",[105,1394,1395],{},"Complete the batch after every intended record has been accepted and every snapshot-backed collection included in the run is complete.",[151,1397,1398,1422],{"sync":153},[155,1399,1400],{"label":157},[159,1401,1403],{"className":287,"code":1402,"language":289,"meta":164,"style":164},"await batch.Complete(cancellationToken);\n",[133,1404,1405],{"__ignoreMap":164},[168,1406,1407,1409,1411,1413,1415,1417,1420],{"class":170,"line":171},[168,1408,1080],{"class":303},[168,1410,805],{"class":299},[168,1412,304],{"class":303},[168,1414,265],{"class":360},[168,1416,364],{"class":303},[168,1418,1419],{"class":299},"cancellationToken",[168,1421,403],{"class":303},[155,1423,1424],{"label":195},[159,1425,1427],{"className":520,"code":1426,"language":205,"meta":164,"style":164},"await batch.complete()\n",[133,1428,1429],{"__ignoreMap":164},[168,1430,1431,1433,1435,1437,1440],{"class":170,"line":171},[168,1432,1080],{"class":384},[168,1434,805],{"class":299},[168,1436,304],{"class":303},[168,1438,1439],{"class":360},"complete",[168,1441,1442],{"class":303},"()\n",[105,1444,1445],{},"Viio tracks each typed collection accepted during the batch. On completion, it reconciles the snapshot-backed collections that were processed and retains accepted event records. Existing snapshot records that were not included are removed.",[226,1447,1448,1461],{},[229,1449,1450],{},[232,1451,1452,1455,1458],{},[235,1453,1454],{},"Processing model",[235,1456,1457],{},"Data types",[235,1459,1460],{},"Completion behavior",[242,1462,1463,1474],{},[232,1464,1465,1468,1471],{},[247,1466,1467],{},"Snapshot",[247,1469,1470],{},"Account, plan, license, employee, group, group member, device",[247,1472,1473],{},"Records missing from the completed snapshot are removed",[232,1475,1476,1479,1482],{},[247,1477,1478],{},"Event",[247,1480,1481],{},"Usage, externally discovered usage, audit log, AI usage, AI cost",[247,1483,1484],{},"Accepted records are processed as events; absence does not remove earlier events",[141,1486,1489],{"icon":1487,"color":1488},"i-lucide-shield-alert","error",[105,1490,1491],{},"Do not complete a batch after a partial snapshot fetch. A filtered or truncated snapshot can remove valid data from Viio. Event-only batches do not perform missing-record reconciliation.",[112,1493,1495],{"id":1494},"abortsyncbatch","AbortSyncBatch",[105,1497,1498],{},"Abort an unfinished batch through its SDK batch object.",[151,1500,1501,1524],{"sync":153},[155,1502,1503],{"label":157},[159,1504,1506],{"className":287,"code":1505,"language":289,"meta":164,"style":164},"await batch.Abort(cancellationToken);\n",[133,1507,1508],{"__ignoreMap":164},[168,1509,1510,1512,1514,1516,1518,1520,1522],{"class":170,"line":171},[168,1511,1080],{"class":303},[168,1513,805],{"class":299},[168,1515,304],{"class":303},[168,1517,273],{"class":360},[168,1519,364],{"class":303},[168,1521,1419],{"class":299},[168,1523,403],{"class":303},[155,1525,1526],{"label":195},[159,1527,1529],{"className":520,"code":1528,"language":205,"meta":164,"style":164},"await batch.abort()\n",[133,1530,1531],{"__ignoreMap":164},[168,1532,1533,1535,1537,1539,1542],{"class":170,"line":171},[168,1534,1080],{"class":384},[168,1536,805],{"class":299},[168,1538,304],{"class":303},[168,1540,1541],{"class":360},"abort",[168,1543,1442],{"class":303},[105,1545,1546],{},"Abort releases only that batch's active lock so a new run can start. A delayed abort for an old batch cannot release a newer batch's lock. Aborting does not roll back records already accepted during the batch and does not run full-snapshot deletion.",[112,1548,1550],{"id":1549},"retry-strategy","Retry Strategy",[105,1552,1553],{},"Wrap the complete write lifecycle so an unsuccessful run is aborted before the error is propagated.",[151,1555,1556,1653],{"sync":153},[155,1557,1558],{"label":157},[159,1559,1561],{"className":287,"code":1560,"language":289,"meta":164,"style":164},"try\n{\n    await WriteBatchRecords(batch, cancellationToken);\n    await batch.Complete(cancellationToken);\n}\ncatch\n{\n    await batch.Abort(CancellationToken.None);\n    throw;\n}\n",[133,1562,1563,1568,1573,1591,1607,1612,1617,1621,1642,1649],{"__ignoreMap":164},[168,1564,1565],{"class":170,"line":171},[168,1566,1567],{"class":384},"try\n",[168,1569,1570],{"class":170,"line":313},[168,1571,1572],{"class":303},"{\n",[168,1574,1575,1578,1581,1583,1585,1587,1589],{"class":170,"line":336},[168,1576,1577],{"class":303},"    await",[168,1579,1580],{"class":360}," WriteBatchRecords",[168,1582,364],{"class":303},[168,1584,854],{"class":299},[168,1586,551],{"class":303},[168,1588,503],{"class":299},[168,1590,403],{"class":303},[168,1592,1593,1595,1597,1599,1601,1603,1605],{"class":170,"line":343},[168,1594,1577],{"class":303},[168,1596,805],{"class":299},[168,1598,304],{"class":303},[168,1600,265],{"class":360},[168,1602,364],{"class":303},[168,1604,1419],{"class":299},[168,1606,403],{"class":303},[168,1608,1609],{"class":170,"line":378},[168,1610,1611],{"class":303},"}\n",[168,1613,1614],{"class":170,"line":406},[168,1615,1616],{"class":384},"catch\n",[168,1618,1619],{"class":170,"line":411},[168,1620,1572],{"class":303},[168,1622,1623,1625,1627,1629,1631,1633,1636,1638,1640],{"class":170,"line":432},[168,1624,1577],{"class":303},[168,1626,805],{"class":299},[168,1628,304],{"class":303},[168,1630,273],{"class":360},[168,1632,364],{"class":303},[168,1634,1635],{"class":299},"CancellationToken",[168,1637,304],{"class":303},[168,1639,513],{"class":299},[168,1641,403],{"class":303},[168,1643,1644,1647],{"class":170,"line":443},[168,1645,1646],{"class":384},"    throw",[168,1648,310],{"class":303},[168,1650,1651],{"class":170,"line":464},[168,1652,1611],{"class":303},[155,1654,1655],{"label":195},[159,1656,1658],{"className":520,"code":1657,"language":205,"meta":164,"style":164},"try:\n    await write_batch_records(batch)\n    await batch.complete()\nexcept BaseException:\n    await batch.abort()\n    raise\n",[133,1659,1660,1667,1680,1692,1702,1714],{"__ignoreMap":164},[168,1661,1662,1665],{"class":170,"line":171},[168,1663,1664],{"class":384},"try",[168,1666,699],{"class":303},[168,1668,1669,1671,1674,1676,1678],{"class":170,"line":313},[168,1670,1577],{"class":384},[168,1672,1673],{"class":360}," write_batch_records",[168,1675,364],{"class":303},[168,1677,854],{"class":360},[168,1679,375],{"class":303},[168,1681,1682,1684,1686,1688,1690],{"class":170,"line":336},[168,1683,1577],{"class":384},[168,1685,805],{"class":299},[168,1687,304],{"class":303},[168,1689,1439],{"class":360},[168,1691,1442],{"class":303},[168,1693,1694,1697,1700],{"class":170,"line":343},[168,1695,1696],{"class":384},"except",[168,1698,1699],{"class":174}," BaseException",[168,1701,699],{"class":303},[168,1703,1704,1706,1708,1710,1712],{"class":170,"line":378},[168,1705,1577],{"class":384},[168,1707,805],{"class":299},[168,1709,304],{"class":303},[168,1711,1541],{"class":360},[168,1713,1442],{"class":303},[168,1715,1716],{"class":170,"line":406},[168,1717,1718],{"class":384},"    raise\n",[105,1720,1721],{},"Use this recovery sequence after a network, source, or validation failure:",[1723,1724,1725,1728,1733,1736,1739],"ol",{},[123,1726,1727],{},"Stop sending records for the failed run.",[123,1729,1730,1731,304],{},"Call ",[133,1732,1495],{},[123,1734,1735],{},"Fix the source or payload problem.",[123,1737,1738],{},"Start a new batch.",[123,1740,1741],{},"Resend every snapshot-backed collection in full and retry event records that were not accepted.",[105,1743,1744],{},"If a records stream is interrupted, requests already accepted by Viio remain associated with the batch. Retry the failed chunk using a new stream, or abort the batch and restart the run. After aborting, resend snapshot-backed collections in full because accepted records are not carried into the new batch.",[105,1746,1747],{},"The SDK batch object retains the batch identifier needed for completion and abort. If the process can terminate between operations, persist that identifier so recovery tooling can identify the unfinished server-side batch.",[112,1749,1751],{"id":1750},"batch-lease","Batch Lease",[105,1753,1754],{},"An active batch has a renewable 15-minute lease. Successfully accepted record requests refresh the lease. If the lease expires, the batch is no longer available and a new batch can acquire the installation lock.",[112,1756,1758],{"id":1757},"authentication-and-authorization-errors","Authentication and Authorization Errors",[226,1760,1761,1771],{},[229,1762,1763],{},[232,1764,1765,1768],{},[235,1766,1767],{},"gRPC status",[235,1769,1770],{},"Meaning",[242,1772,1773,1783],{},[232,1774,1775,1780],{},[247,1776,1777],{},[133,1778,1779],{},"Unauthenticated",[247,1781,1782],{},"The API key is missing, inactive, malformed, or could not be verified",[232,1784,1785,1790],{},[247,1786,1787],{},[133,1788,1789],{},"PermissionDenied",[247,1791,1792,1793,1795],{},"The key lacks ",[133,1794,135],{}," or the installation or batch belongs to another workspace",[105,1797,1798],{},"The SDK raises the corresponding authentication, protocol, or transport error. API keys are workspace-scoped, so a key cannot start, write to, complete, or abort a batch owned by another workspace. See the language-specific SDK guide for concrete error types.",[1800,1801],"read-more",{"title":1802,"to":1259},"Browse model properties",[1804,1805,1806],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}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);}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 pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":164,"searchDepth":171,"depth":313,"links":1808},[1809,1810,1811,1812,1813,1816,1817,1818,1819,1820],{"id":114,"depth":313,"text":115},{"id":223,"depth":313,"text":224},{"id":279,"depth":313,"text":280},{"id":717,"depth":313,"text":718},{"id":936,"depth":313,"text":937,"children":1814},[1815],{"id":1289,"depth":336,"text":1290},{"id":1391,"depth":313,"text":1392},{"id":1494,"depth":313,"text":1495},{"id":1549,"depth":313,"text":1550},{"id":1750,"depth":313,"text":1751},{"id":1757,"depth":313,"text":1758},"2026-08-06","2026-07-30","Install an SDK and safely start, stream, complete, retry, and abort Sync API batches.","md",null,{},{"title":1828,"description":1829},"Viio Sync API Quickstart","Install a Viio Sync API SDK and learn how to start, stream, complete, retry, and abort batches without removing valid source records.","9mmAHpc8jmhf0pbbFuU3Q2BTLCaCa0s6zdXBh_vOzpo",[1832,1834],{"title":58,"path":54,"stem":55,"description":1833,"children":-1},"Use the Viio Sync API to push data from custom, on-premises, or customer-managed software into Viio.",{"title":1835,"path":65,"stem":1836,"description":1837,"children":-1},"AWS Lambda with Python","3.sync-api\u002F6.aws-lambda-python","Run a scheduled Microsoft Entra employee sync from AWS Lambda with the Viio Python SDK.",1787319043523]