[{"data":1,"prerenderedAt":3140},["ShallowReactive",2],{"blog:post:create-whatsapp-groups-from-google-sheets":3},{"id":4,"title":5,"author":6,"body":7,"date":3122,"description":3123,"extension":3124,"links_to":3125,"meta":3130,"navigation":421,"path":3131,"seo":3132,"stem":3133,"tags":3134,"updated":3138,"__hash__":3139},"blog\u002Fblog\u002Fcreate-whatsapp-groups-from-google-sheets.md","Create WhatsApp Groups from Google Sheets","Wapito team",{"type":8,"value":9,"toc":3111},"minimark",[10,35,42,47,50,123,135,139,180,184,191,261,379,386,541,560,564,578,1879,1893,1896,1945,1949,1956,2385,2407,2411,2414,2782,2801,2805,2808,2870,2892,2916,2920,2923,3032,3054,3058,3061,3104,3107],[11,12,13,14,19,20,24,25,29,30,34],"p",{},"A spreadsheet is where most small operations already live: the list of customers for this\nmonth's cohort, the clients who each get a project group, the parents of every class. Turning\neach row into a WhatsApp group by hand — create it on the phone, add the people, copy the invite\nlink back into the sheet — is the kind of task that eats an afternoon a week. This tutorial\nreplaces it with about eighty lines of Google Apps Script and a handful of Wapito endpoints:\n",[15,16,18],"a",{"href":17},"\u002Fwhatsapp-api\u002Fcreate-group\u002F","create a group",", ",[15,21,23],{"href":22},"\u002Fwhatsapp-api\u002Fgroup-participants\u002F","add participants","\nand read the member list back, ",[15,26,28],{"href":27},"\u002Fwhatsapp-api\u002Fgroup-invite-link\u002F","read the invite link"," and\n",[15,31,33],{"href":32},"\u002Fwhatsapp-api\u002Fsend-group-message\u002F","send the first message",".\nIt ends with a variant that adds new rows to one existing group instead, and an n8n version for\nteams that would rather not write code at all.",[11,36,37,38],{},"There is no Cloud API version of this walkthrough, because Meta's official API has no group\nendpoints. That is the whole reason a linked-number API exists, and it comes with a\nresponsibility we will keep coming back to: ",[39,40,41],"strong",{},"only put people in a group who expect to be in it.",[43,44,46],"h2",{"id":45},"what-you-will-build","What you will build",[11,48,49],{},"A sheet with one row per group to create:",[51,52,53,81],"table",{},[54,55,56],"thead",{},[57,58,59,63,66,69,72,75,78],"tr",{},[60,61,62],"th",{},"A: Group name",[60,64,65],{},"B: Description",[60,67,68],{},"C: Participants",[60,70,71],{},"D: Group id",[60,73,74],{},"E: Invite link",[60,76,77],{},"F: Status",[60,79,80],{},"G: Not added",[82,83,84,104],"tbody",{},[57,85,86,90,93,96,98,100,102],{},[87,88,89],"td",{},"Acme Launch Team",[87,91,92],{},"Q3 launch coordination",[87,94,95],{},"+15551234567, +15559876543",[87,97],{},[87,99],{},[87,101],{},[87,103],{},[57,105,106,109,112,115,117,119,121],{},[87,107,108],{},"Cohort 12 — Mondays",[87,110,111],{},"Class chat for cohort 12",[87,113,114],{},"+15550001111, +15550002222, +15550003333",[87,116],{},[87,118],{},[87,120],{},[87,122],{},[11,124,125,126,130,131,134],{},"Columns A–C are yours. The script fills D–G: the group's id, its ",[127,128,129],"code",{},"chat.whatsapp.com"," link, either\n",[127,132,133],{},"created"," or an error message, and the numbers from column C that WhatsApp did not let into the\ngroup — the people you will send the link to instead. It skips any row that already has a group\nid so you can run it again safely. Each new group gets a welcome message so the first thing\nmembers see is context rather than an empty chat.",[43,136,138],{"id":137},"before-you-start","Before you start",[140,141,142,155,166,177],"ul",{},[143,144,145,146,149,150,154],"li",{},"A Wapito channel with a number that is ",[39,147,148],{},"warmed up",". Group creation is the highest ban-risk\noperation on the API — WhatsApp watches it closely — and a number linked yesterday should not\ncreate twenty groups today. The ",[15,151,153],{"href":152},"\u002Fdocs\u002Fanti-ban-guide\u002F","anti-ban guide"," explains the warm-up\nladder; give the number a week.",[143,156,157,158,161,162,165],{},"The channel token from the dashboard's API tab. In Apps Script it goes into ",[39,159,160],{},"Project\nSettings → Script Properties"," as ",[127,163,164],{},"WAPITO_TOKEN",", never into the code.",[143,167,168,169,172,173,176],{},"Participants in international format, ",[127,170,171],{},"+"," and country code, separated by commas. The API also\naccepts bare digits and ",[127,174,175],{},"@s.whatsapp.net"," ids, but a sheet is friendlier with one format.",[143,178,179],{},"Consent. A row in a spreadsheet is not consent. If the people in column C did not agree to be\nadded to a WhatsApp group, use the invite-link variant below instead of adding them.",[43,181,183],{"id":182},"step-1-the-api-calls-in-isolation","Step 1 — the API calls, in isolation",[11,185,186,187,190],{},"Before the script, the requests it makes, so you can run them from curl first and know what each\nreturns. The ",[15,188,189],{"href":17},"group creation"," call takes a subject, an optional\ndescription and the initial participants:",[192,193,198],"pre",{"className":194,"code":195,"language":196,"meta":197,"style":197},"language-bash shiki shiki-themes github-light-default github-dark-default","curl -X POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"subject\": \"Acme Launch Team\", \"description\": \"Q3 launch coordination\", \"participants\": [\"+15551234567\", \"+15559876543\"]}'\n","bash","",[127,199,200,224,242,252],{"__ignoreMap":197},[201,202,205,209,213,217,220],"span",{"class":203,"line":204},"line",1,[201,206,208],{"class":207},"sTDnQ","curl",[201,210,212],{"class":211},"sHrmB"," -X",[201,214,216],{"class":215},"sSVrQ"," POST",[201,218,219],{"class":215}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups",[201,221,223],{"class":222},"sjeE4"," \\\n",[201,225,227,230,233,237,240],{"class":203,"line":226},2,[201,228,229],{"class":211},"  -H",[201,231,232],{"class":215}," \"Authorization: Bearer ",[201,234,236],{"class":235},"s4rv2","$WAPITO_TOKEN",[201,238,239],{"class":215},"\"",[201,241,223],{"class":222},[201,243,245,247,250],{"class":203,"line":244},3,[201,246,229],{"class":211},[201,248,249],{"class":215}," \"Content-Type: application\u002Fjson\"",[201,251,223],{"class":222},[201,253,255,258],{"class":203,"line":254},4,[201,256,257],{"class":211},"  -d",[201,259,260],{"class":215}," '{\"subject\": \"Acme Launch Team\", \"description\": \"Q3 launch coordination\", \"participants\": [\"+15551234567\", \"+15559876543\"]}'\n",[192,262,266],{"className":263,"code":264,"language":265,"meta":197,"style":197},"language-json shiki shiki-themes github-light-default github-dark-default","{\n  \"id\": \"120363041234567890@g.us\",\n  \"subject\": \"Acme Launch Team\",\n  \"invite_code\": \"HkQ2ZpL9vRtAeYm1\",\n  \"participants_count\": 3,\n  \"settings\": { \"member_add_mode\": \"admin_add\", \"membership_approval\": false, \"messages_admin_only\": false, \"info_admin_only\": false }\n}\n","json",[127,267,268,273,288,300,312,325,373],{"__ignoreMap":197},[201,269,270],{"class":203,"line":204},[201,271,272],{"class":235},"{\n",[201,274,275,279,282,285],{"class":203,"line":226},[201,276,278],{"class":277},"sjgCt","  \"id\"",[201,280,281],{"class":235},": ",[201,283,284],{"class":215},"\"120363041234567890@g.us\"",[201,286,287],{"class":235},",\n",[201,289,290,293,295,298],{"class":203,"line":244},[201,291,292],{"class":277},"  \"subject\"",[201,294,281],{"class":235},[201,296,297],{"class":215},"\"Acme Launch Team\"",[201,299,287],{"class":235},[201,301,302,305,307,310],{"class":203,"line":254},[201,303,304],{"class":277},"  \"invite_code\"",[201,306,281],{"class":235},[201,308,309],{"class":215},"\"HkQ2ZpL9vRtAeYm1\"",[201,311,287],{"class":235},[201,313,315,318,320,323],{"class":203,"line":314},5,[201,316,317],{"class":277},"  \"participants_count\"",[201,319,281],{"class":235},[201,321,322],{"class":211},"3",[201,324,287],{"class":235},[201,326,328,331,334,337,339,342,344,347,349,352,354,357,359,361,363,366,368,370],{"class":203,"line":327},6,[201,329,330],{"class":277},"  \"settings\"",[201,332,333],{"class":235},": { ",[201,335,336],{"class":277},"\"member_add_mode\"",[201,338,281],{"class":235},[201,340,341],{"class":215},"\"admin_add\"",[201,343,19],{"class":235},[201,345,346],{"class":277},"\"membership_approval\"",[201,348,281],{"class":235},[201,350,351],{"class":211},"false",[201,353,19],{"class":235},[201,355,356],{"class":277},"\"messages_admin_only\"",[201,358,281],{"class":235},[201,360,351],{"class":211},[201,362,19],{"class":235},[201,364,365],{"class":277},"\"info_admin_only\"",[201,367,281],{"class":235},[201,369,351],{"class":211},[201,371,372],{"class":235}," }\n",[201,374,376],{"class":203,"line":375},7,[201,377,378],{"class":235},"}\n",[11,380,381,382,385],{},"The ",[127,383,384],{},"id"," is the group's address for every later call. Then the invite link, the member list,\nthe participants you want to add later, and the first message, each addressed to that id:",[192,387,389],{"className":194,"code":388,"language":196,"meta":197,"style":197},"curl https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F120363041234567890@g.us\u002Finvite \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\"\n# {\"code\": \"HkQ2ZpL9vRtAeYm1\", \"link\": \"https:\u002F\u002Fchat.whatsapp.com\u002FHkQ2ZpL9vRtAeYm1\"}\n\ncurl https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F120363041234567890@g.us\u002Fparticipants \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\"\n# {\"participants\": [{\"id\": \"15551234567@s.whatsapp.net\", \"phone\": \"15551234567\", \"lid\": null, \"name\": null, \"role\": \"member\", \"joined_at\": \"2026-09-15T09:14:00.000Z\"}, …], \"count\": 3}\n\ncurl -X POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F120363041234567890@g.us\u002Fparticipants \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\" -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"participants\": [\"+15550004444\"]}'\n# {\"results\": [{\"id\": \"15550004444@s.whatsapp.net\", \"status\": \"added\"}]}\n\ncurl -X POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Ftext \\\n  -H \"Authorization: Bearer $WAPITO_TOKEN\" -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\"to\": \"120363041234567890@g.us\", \"body\": \"Welcome! This is the launch coordination group.\"}'\n",[127,390,391,400,411,417,423,432,442,447,452,465,483,491,497,502,516,533],{"__ignoreMap":197},[201,392,393,395,398],{"class":203,"line":204},[201,394,208],{"class":207},[201,396,397],{"class":215}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F120363041234567890@g.us\u002Finvite",[201,399,223],{"class":222},[201,401,402,404,406,408],{"class":203,"line":226},[201,403,229],{"class":211},[201,405,232],{"class":215},[201,407,236],{"class":235},[201,409,410],{"class":215},"\"\n",[201,412,413],{"class":203,"line":244},[201,414,416],{"class":415},"sU953","# {\"code\": \"HkQ2ZpL9vRtAeYm1\", \"link\": \"https:\u002F\u002Fchat.whatsapp.com\u002FHkQ2ZpL9vRtAeYm1\"}\n",[201,418,419],{"class":203,"line":254},[201,420,422],{"emptyLinePlaceholder":421},true,"\n",[201,424,425,427,430],{"class":203,"line":314},[201,426,208],{"class":207},[201,428,429],{"class":215}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F120363041234567890@g.us\u002Fparticipants",[201,431,223],{"class":222},[201,433,434,436,438,440],{"class":203,"line":327},[201,435,229],{"class":211},[201,437,232],{"class":215},[201,439,236],{"class":235},[201,441,410],{"class":215},[201,443,444],{"class":203,"line":375},[201,445,446],{"class":415},"# {\"participants\": [{\"id\": \"15551234567@s.whatsapp.net\", \"phone\": \"15551234567\", \"lid\": null, \"name\": null, \"role\": \"member\", \"joined_at\": \"2026-09-15T09:14:00.000Z\"}, …], \"count\": 3}\n",[201,448,450],{"class":203,"line":449},8,[201,451,422],{"emptyLinePlaceholder":421},[201,453,455,457,459,461,463],{"class":203,"line":454},9,[201,456,208],{"class":207},[201,458,212],{"class":211},[201,460,216],{"class":215},[201,462,429],{"class":215},[201,464,223],{"class":222},[201,466,468,470,472,474,476,479,481],{"class":203,"line":467},10,[201,469,229],{"class":211},[201,471,232],{"class":215},[201,473,236],{"class":235},[201,475,239],{"class":215},[201,477,478],{"class":211}," -H",[201,480,249],{"class":215},[201,482,223],{"class":222},[201,484,486,488],{"class":203,"line":485},11,[201,487,257],{"class":211},[201,489,490],{"class":215}," '{\"participants\": [\"+15550004444\"]}'\n",[201,492,494],{"class":203,"line":493},12,[201,495,496],{"class":415},"# {\"results\": [{\"id\": \"15550004444@s.whatsapp.net\", \"status\": \"added\"}]}\n",[201,498,500],{"class":203,"line":499},13,[201,501,422],{"emptyLinePlaceholder":421},[201,503,505,507,509,511,514],{"class":203,"line":504},14,[201,506,208],{"class":207},[201,508,212],{"class":211},[201,510,216],{"class":215},[201,512,513],{"class":215}," https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Ftext",[201,515,223],{"class":222},[201,517,519,521,523,525,527,529,531],{"class":203,"line":518},15,[201,520,229],{"class":211},[201,522,232],{"class":215},[201,524,236],{"class":235},[201,526,239],{"class":215},[201,528,478],{"class":211},[201,530,249],{"class":215},[201,532,223],{"class":222},[201,534,536,538],{"class":203,"line":535},16,[201,537,257],{"class":211},[201,539,540],{"class":215}," '{\"to\": \"120363041234567890@g.us\", \"body\": \"Welcome! This is the launch coordination group.\"}'\n",[11,542,543,544,547,548,551,552,555,556,559],{},"One detail matters for the script. The add-participants call is the only one that answers per\nperson: someone whose privacy settings do not allow strangers to add them comes back with\n",[127,545,546],{},"status: \"invite_required\""," instead of ",[127,549,550],{},"added",". That is not an error and must not be retried; it\nis WhatsApp telling you to send that person the link instead. The create call gives no such\nverdict. WhatsApp adds whom it can, the rest are simply not in the group, and the response\ncarries a ",[127,553,554],{},"participants_count"," (your own number included), not a list of who was left out. So\nafter creating each group the script reads the member list back —\n",[127,557,558],{},"GET \u002Fgroups\u002F{id}\u002Fparticipants"," — and writes the numbers from column C that are not in it to\ncolumn G, which is the list Step 3 works from.",[43,561,563],{"id":562},"step-2-the-apps-script","Step 2 — the Apps Script",[11,565,566,567,570,571,574,575,577],{},"Open the sheet, choose ",[39,568,569],{},"Extensions → Apps Script",", replace the contents of ",[127,572,573],{},"Code.gs"," with the\nfollowing, and save. Set ",[127,576,164],{}," in Script Properties before the first run.",[192,579,583],{"className":580,"code":581,"language":582,"meta":197,"style":197},"language-javascript shiki shiki-themes github-light-default github-dark-default","\u002F\u002F Create one WhatsApp group per row, via the Wapito API. Columns:\n\u002F\u002F A subject · B description · C participants (comma-separated, +E.164) · D group id · E invite link · F status · G not added\nconst BASE_URL = 'https:\u002F\u002Fapi.wapito.com\u002Fv1';\nconst SHEET_NAME = 'Groups';\nconst FIRST_ROW = 2; \u002F\u002F row 1 is the header\n\nfunction wapito_(method, path, payload) {\n  const token = PropertiesService.getScriptProperties().getProperty('WAPITO_TOKEN');\n  const res = UrlFetchApp.fetch(BASE_URL + path, {\n    method,\n    contentType: 'application\u002Fjson',\n    headers: { Authorization: 'Bearer ' + token },\n    payload: payload ? JSON.stringify(payload) : undefined,\n    muteHttpExceptions: true, \u002F\u002F we branch on the error code ourselves\n  });\n  const body = JSON.parse(res.getContentText() || '{}');\n  if (res.getResponseCode() >= 400) {\n    const err = body.error || {};\n    throw new Error((err.code || res.getResponseCode()) + (err.details ? ' ' + JSON.stringify(err.details) : ''));\n  }\n  return body;\n}\n\nfunction numbersIn_(cell) {\n  return String(cell).split(',').map((p) => p.trim()).filter(Boolean);\n}\n\n\u002F\u002F The numbers from column C that did not make it into the group. WhatsApp adds\n\u002F\u002F whom it can and leaves the rest out without saying so; the create response\n\u002F\u002F only carries a count, so the member list is read back and compared.\nfunction notAdded_(groupPath, requested) {\n  const list = wapito_('get', groupPath + '\u002Fparticipants');\n  if (list.count >= requested.length + 1) return []; \u002F\u002F everyone, plus your own number\n  const present = new Set(list.participants.map((p) => p.phone).filter(Boolean));\n  return requested.filter((number) => !present.has(number.replace(\u002F\\D\u002Fg, '')));\n}\n\nfunction createGroupsFromSheet() {\n  const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);\n  const rows = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow() - FIRST_ROW + 1, 7).getValues();\n\n  rows.forEach((row, i) => {\n    const [subject, description, participantsCell, groupId] = row;\n    const rowNumber = FIRST_ROW + i;\n    if (!subject || groupId) return; \u002F\u002F blank row, or already created on a previous run\n\n    const participants = numbersIn_(participantsCell);\n\n    let group;\n    try {\n      group = wapito_('post', '\u002Fgroups', { subject, description: description || undefined, participants });\n    } catch (e) {\n      sheet.getRange(rowNumber, 6).setValue('error: ' + e.message);\n      Utilities.sleep(15000);\n      return;\n    }\n    \u002F\u002F Write the id before anything else can fail: a re-run must never create this group twice.\n    sheet.getRange(rowNumber, 4).setValue(group.id);\n\n    try {\n      const groupPath = '\u002Fgroups\u002F' + encodeURIComponent(group.id);\n      const invite = wapito_('get', groupPath + '\u002Finvite');\n      sheet.getRange(rowNumber, 5).setValue(invite.link);\n      sheet.getRange(rowNumber, 7).setValue(notAdded_(groupPath, participants).join(', '));\n      wapito_('post', '\u002Fmessages\u002Ftext', {\n        to: group.id,\n        body: 'Welcome to ' + subject + '. ' + (description || 'Say hello!'),\n      });\n      sheet.getRange(rowNumber, 6).setValue('created');\n    } catch (e) {\n      sheet.getRange(rowNumber, 6).setValue('created, then: ' + e.message);\n    }\n\n    \u002F\u002F The channel's send queue paces messages on its own; the pause here keeps\n    \u002F\u002F group creation itself unhurried, which is the part WhatsApp watches.\n    Utilities.sleep(15000);\n  });\n}\n","javascript",[127,584,585,590,595,612,626,644,648,676,706,732,737,747,760,788,801,806,839,861,880,934,940,949,954,959,974,1025,1030,1035,1041,1047,1053,1073,1100,1132,1168,1222,1227,1232,1243,1271,1327,1332,1358,1393,1410,1437,1442,1457,1462,1471,1479,1509,1521,1550,1566,1574,1580,1586,1606,1611,1618,1639,1664,1683,1716,1734,1740,1772,1778,1800,1809,1833,1838,1843,1849,1855,1869,1874],{"__ignoreMap":197},[201,586,587],{"class":203,"line":204},[201,588,589],{"class":415},"\u002F\u002F Create one WhatsApp group per row, via the Wapito API. Columns:\n",[201,591,592],{"class":203,"line":226},[201,593,594],{"class":415},"\u002F\u002F A subject · B description · C participants (comma-separated, +E.164) · D group id · E invite link · F status · G not added\n",[201,596,597,600,603,606,609],{"class":203,"line":244},[201,598,599],{"class":222},"const",[201,601,602],{"class":211}," BASE_URL",[201,604,605],{"class":222}," =",[201,607,608],{"class":215}," 'https:\u002F\u002Fapi.wapito.com\u002Fv1'",[201,610,611],{"class":235},";\n",[201,613,614,616,619,621,624],{"class":203,"line":254},[201,615,599],{"class":222},[201,617,618],{"class":211}," SHEET_NAME",[201,620,605],{"class":222},[201,622,623],{"class":215}," 'Groups'",[201,625,611],{"class":235},[201,627,628,630,633,635,638,641],{"class":203,"line":314},[201,629,599],{"class":222},[201,631,632],{"class":211}," FIRST_ROW",[201,634,605],{"class":222},[201,636,637],{"class":211}," 2",[201,639,640],{"class":235},"; ",[201,642,643],{"class":415},"\u002F\u002F row 1 is the header\n",[201,645,646],{"class":203,"line":327},[201,647,422],{"emptyLinePlaceholder":421},[201,649,650,653,657,660,663,665,668,670,673],{"class":203,"line":375},[201,651,652],{"class":222},"function",[201,654,656],{"class":655},"sbjLL"," wapito_",[201,658,659],{"class":235},"(",[201,661,662],{"class":207},"method",[201,664,19],{"class":235},[201,666,667],{"class":207},"path",[201,669,19],{"class":235},[201,671,672],{"class":207},"payload",[201,674,675],{"class":235},") {\n",[201,677,678,681,684,686,689,692,695,698,700,703],{"class":203,"line":449},[201,679,680],{"class":222},"  const",[201,682,683],{"class":211}," token",[201,685,605],{"class":222},[201,687,688],{"class":235}," PropertiesService.",[201,690,691],{"class":655},"getScriptProperties",[201,693,694],{"class":235},"().",[201,696,697],{"class":655},"getProperty",[201,699,659],{"class":235},[201,701,702],{"class":215},"'WAPITO_TOKEN'",[201,704,705],{"class":235},");\n",[201,707,708,710,713,715,718,721,723,726,729],{"class":203,"line":454},[201,709,680],{"class":222},[201,711,712],{"class":211}," res",[201,714,605],{"class":222},[201,716,717],{"class":235}," UrlFetchApp.",[201,719,720],{"class":655},"fetch",[201,722,659],{"class":235},[201,724,725],{"class":211},"BASE_URL",[201,727,728],{"class":222}," +",[201,730,731],{"class":235}," path, {\n",[201,733,734],{"class":203,"line":467},[201,735,736],{"class":235},"    method,\n",[201,738,739,742,745],{"class":203,"line":485},[201,740,741],{"class":235},"    contentType: ",[201,743,744],{"class":215},"'application\u002Fjson'",[201,746,287],{"class":235},[201,748,749,752,755,757],{"class":203,"line":493},[201,750,751],{"class":235},"    headers: { Authorization: ",[201,753,754],{"class":215},"'Bearer '",[201,756,728],{"class":222},[201,758,759],{"class":235}," token },\n",[201,761,762,765,768,771,774,777,780,783,786],{"class":203,"line":499},[201,763,764],{"class":235},"    payload: payload ",[201,766,767],{"class":222},"?",[201,769,770],{"class":211}," JSON",[201,772,773],{"class":235},".",[201,775,776],{"class":655},"stringify",[201,778,779],{"class":235},"(payload) ",[201,781,782],{"class":222},":",[201,784,785],{"class":211}," undefined",[201,787,287],{"class":235},[201,789,790,793,796,798],{"class":203,"line":504},[201,791,792],{"class":235},"    muteHttpExceptions: ",[201,794,795],{"class":211},"true",[201,797,19],{"class":235},[201,799,800],{"class":415},"\u002F\u002F we branch on the error code ourselves\n",[201,802,803],{"class":203,"line":518},[201,804,805],{"class":235},"  });\n",[201,807,808,810,813,815,817,819,822,825,828,831,834,837],{"class":203,"line":535},[201,809,680],{"class":222},[201,811,812],{"class":211}," body",[201,814,605],{"class":222},[201,816,770],{"class":211},[201,818,773],{"class":235},[201,820,821],{"class":655},"parse",[201,823,824],{"class":235},"(res.",[201,826,827],{"class":655},"getContentText",[201,829,830],{"class":235},"() ",[201,832,833],{"class":222},"||",[201,835,836],{"class":215}," '{}'",[201,838,705],{"class":235},[201,840,842,845,848,851,853,856,859],{"class":203,"line":841},17,[201,843,844],{"class":222},"  if",[201,846,847],{"class":235}," (res.",[201,849,850],{"class":655},"getResponseCode",[201,852,830],{"class":235},[201,854,855],{"class":222},">=",[201,857,858],{"class":211}," 400",[201,860,675],{"class":235},[201,862,864,867,870,872,875,877],{"class":203,"line":863},18,[201,865,866],{"class":222},"    const",[201,868,869],{"class":211}," err",[201,871,605],{"class":222},[201,873,874],{"class":235}," body.error ",[201,876,833],{"class":222},[201,878,879],{"class":235}," {};\n",[201,881,883,886,889,892,895,897,900,902,905,907,910,912,915,917,919,921,923,926,928,931],{"class":203,"line":882},19,[201,884,885],{"class":222},"    throw",[201,887,888],{"class":222}," new",[201,890,891],{"class":655}," Error",[201,893,894],{"class":235},"((err.code ",[201,896,833],{"class":222},[201,898,899],{"class":235}," res.",[201,901,850],{"class":655},[201,903,904],{"class":235},"()) ",[201,906,171],{"class":222},[201,908,909],{"class":235}," (err.details ",[201,911,767],{"class":222},[201,913,914],{"class":215}," ' '",[201,916,728],{"class":222},[201,918,770],{"class":211},[201,920,773],{"class":235},[201,922,776],{"class":655},[201,924,925],{"class":235},"(err.details) ",[201,927,782],{"class":222},[201,929,930],{"class":215}," ''",[201,932,933],{"class":235},"));\n",[201,935,937],{"class":203,"line":936},20,[201,938,939],{"class":235},"  }\n",[201,941,943,946],{"class":203,"line":942},21,[201,944,945],{"class":222},"  return",[201,947,948],{"class":235}," body;\n",[201,950,952],{"class":203,"line":951},22,[201,953,378],{"class":235},[201,955,957],{"class":203,"line":956},23,[201,958,422],{"emptyLinePlaceholder":421},[201,960,962,964,967,969,972],{"class":203,"line":961},24,[201,963,652],{"class":222},[201,965,966],{"class":655}," numbersIn_",[201,968,659],{"class":235},[201,970,971],{"class":207},"cell",[201,973,675],{"class":235},[201,975,977,979,982,985,988,990,993,996,999,1002,1004,1007,1010,1013,1016,1019,1022],{"class":203,"line":976},25,[201,978,945],{"class":222},[201,980,981],{"class":655}," String",[201,983,984],{"class":235},"(cell).",[201,986,987],{"class":655},"split",[201,989,659],{"class":235},[201,991,992],{"class":215},"','",[201,994,995],{"class":235},").",[201,997,998],{"class":655},"map",[201,1000,1001],{"class":235},"((",[201,1003,11],{"class":207},[201,1005,1006],{"class":235},") ",[201,1008,1009],{"class":222},"=>",[201,1011,1012],{"class":235}," p.",[201,1014,1015],{"class":655},"trim",[201,1017,1018],{"class":235},"()).",[201,1020,1021],{"class":655},"filter",[201,1023,1024],{"class":235},"(Boolean);\n",[201,1026,1028],{"class":203,"line":1027},26,[201,1029,378],{"class":235},[201,1031,1033],{"class":203,"line":1032},27,[201,1034,422],{"emptyLinePlaceholder":421},[201,1036,1038],{"class":203,"line":1037},28,[201,1039,1040],{"class":415},"\u002F\u002F The numbers from column C that did not make it into the group. WhatsApp adds\n",[201,1042,1044],{"class":203,"line":1043},29,[201,1045,1046],{"class":415},"\u002F\u002F whom it can and leaves the rest out without saying so; the create response\n",[201,1048,1050],{"class":203,"line":1049},30,[201,1051,1052],{"class":415},"\u002F\u002F only carries a count, so the member list is read back and compared.\n",[201,1054,1056,1058,1061,1063,1066,1068,1071],{"class":203,"line":1055},31,[201,1057,652],{"class":222},[201,1059,1060],{"class":655}," notAdded_",[201,1062,659],{"class":235},[201,1064,1065],{"class":207},"groupPath",[201,1067,19],{"class":235},[201,1069,1070],{"class":207},"requested",[201,1072,675],{"class":235},[201,1074,1076,1078,1081,1083,1085,1087,1090,1093,1095,1098],{"class":203,"line":1075},32,[201,1077,680],{"class":222},[201,1079,1080],{"class":211}," list",[201,1082,605],{"class":222},[201,1084,656],{"class":655},[201,1086,659],{"class":235},[201,1088,1089],{"class":215},"'get'",[201,1091,1092],{"class":235},", groupPath ",[201,1094,171],{"class":222},[201,1096,1097],{"class":215}," '\u002Fparticipants'",[201,1099,705],{"class":235},[201,1101,1103,1105,1108,1110,1113,1116,1118,1121,1123,1126,1129],{"class":203,"line":1102},33,[201,1104,844],{"class":222},[201,1106,1107],{"class":235}," (list.count ",[201,1109,855],{"class":222},[201,1111,1112],{"class":235}," requested.",[201,1114,1115],{"class":211},"length",[201,1117,728],{"class":222},[201,1119,1120],{"class":211}," 1",[201,1122,1006],{"class":235},[201,1124,1125],{"class":222},"return",[201,1127,1128],{"class":235}," []; ",[201,1130,1131],{"class":415},"\u002F\u002F everyone, plus your own number\n",[201,1133,1135,1137,1140,1142,1144,1147,1150,1152,1154,1156,1158,1160,1163,1165],{"class":203,"line":1134},34,[201,1136,680],{"class":222},[201,1138,1139],{"class":211}," present",[201,1141,605],{"class":222},[201,1143,888],{"class":222},[201,1145,1146],{"class":655}," Set",[201,1148,1149],{"class":235},"(list.participants.",[201,1151,998],{"class":655},[201,1153,1001],{"class":235},[201,1155,11],{"class":207},[201,1157,1006],{"class":235},[201,1159,1009],{"class":222},[201,1161,1162],{"class":235}," p.phone).",[201,1164,1021],{"class":655},[201,1166,1167],{"class":235},"(Boolean));\n",[201,1169,1171,1173,1175,1177,1179,1182,1184,1186,1189,1192,1195,1198,1201,1203,1206,1209,1211,1214,1216,1219],{"class":203,"line":1170},35,[201,1172,945],{"class":222},[201,1174,1112],{"class":235},[201,1176,1021],{"class":655},[201,1178,1001],{"class":235},[201,1180,1181],{"class":207},"number",[201,1183,1006],{"class":235},[201,1185,1009],{"class":222},[201,1187,1188],{"class":222}," !",[201,1190,1191],{"class":235},"present.",[201,1193,1194],{"class":655},"has",[201,1196,1197],{"class":235},"(number.",[201,1199,1200],{"class":655},"replace",[201,1202,659],{"class":235},[201,1204,1205],{"class":215},"\u002F",[201,1207,1208],{"class":211},"\\D",[201,1210,1205],{"class":215},[201,1212,1213],{"class":222},"g",[201,1215,19],{"class":235},[201,1217,1218],{"class":215},"''",[201,1220,1221],{"class":235},")));\n",[201,1223,1225],{"class":203,"line":1224},36,[201,1226,378],{"class":235},[201,1228,1230],{"class":203,"line":1229},37,[201,1231,422],{"emptyLinePlaceholder":421},[201,1233,1235,1237,1240],{"class":203,"line":1234},38,[201,1236,652],{"class":222},[201,1238,1239],{"class":655}," createGroupsFromSheet",[201,1241,1242],{"class":235},"() {\n",[201,1244,1246,1248,1251,1253,1256,1259,1261,1264,1266,1269],{"class":203,"line":1245},39,[201,1247,680],{"class":222},[201,1249,1250],{"class":211}," sheet",[201,1252,605],{"class":222},[201,1254,1255],{"class":235}," SpreadsheetApp.",[201,1257,1258],{"class":655},"getActive",[201,1260,694],{"class":235},[201,1262,1263],{"class":655},"getSheetByName",[201,1265,659],{"class":235},[201,1267,1268],{"class":211},"SHEET_NAME",[201,1270,705],{"class":235},[201,1272,1274,1276,1279,1281,1284,1287,1289,1292,1294,1297,1300,1303,1305,1308,1310,1312,1314,1316,1319,1321,1324],{"class":203,"line":1273},40,[201,1275,680],{"class":222},[201,1277,1278],{"class":211}," rows",[201,1280,605],{"class":222},[201,1282,1283],{"class":235}," sheet.",[201,1285,1286],{"class":655},"getRange",[201,1288,659],{"class":235},[201,1290,1291],{"class":211},"FIRST_ROW",[201,1293,19],{"class":235},[201,1295,1296],{"class":211},"1",[201,1298,1299],{"class":235},", sheet.",[201,1301,1302],{"class":655},"getLastRow",[201,1304,830],{"class":235},[201,1306,1307],{"class":222},"-",[201,1309,632],{"class":211},[201,1311,728],{"class":222},[201,1313,1120],{"class":211},[201,1315,19],{"class":235},[201,1317,1318],{"class":211},"7",[201,1320,995],{"class":235},[201,1322,1323],{"class":655},"getValues",[201,1325,1326],{"class":235},"();\n",[201,1328,1330],{"class":203,"line":1329},41,[201,1331,422],{"emptyLinePlaceholder":421},[201,1333,1335,1338,1341,1343,1346,1348,1351,1353,1355],{"class":203,"line":1334},42,[201,1336,1337],{"class":235},"  rows.",[201,1339,1340],{"class":655},"forEach",[201,1342,1001],{"class":235},[201,1344,1345],{"class":207},"row",[201,1347,19],{"class":235},[201,1349,1350],{"class":207},"i",[201,1352,1006],{"class":235},[201,1354,1009],{"class":222},[201,1356,1357],{"class":235}," {\n",[201,1359,1361,1363,1366,1369,1371,1374,1376,1379,1381,1384,1387,1390],{"class":203,"line":1360},43,[201,1362,866],{"class":222},[201,1364,1365],{"class":235}," [",[201,1367,1368],{"class":211},"subject",[201,1370,19],{"class":235},[201,1372,1373],{"class":211},"description",[201,1375,19],{"class":235},[201,1377,1378],{"class":211},"participantsCell",[201,1380,19],{"class":235},[201,1382,1383],{"class":211},"groupId",[201,1385,1386],{"class":235},"] ",[201,1388,1389],{"class":222},"=",[201,1391,1392],{"class":235}," row;\n",[201,1394,1396,1398,1401,1403,1405,1407],{"class":203,"line":1395},44,[201,1397,866],{"class":222},[201,1399,1400],{"class":211}," rowNumber",[201,1402,605],{"class":222},[201,1404,632],{"class":211},[201,1406,728],{"class":222},[201,1408,1409],{"class":235}," i;\n",[201,1411,1413,1416,1419,1422,1425,1427,1430,1432,1434],{"class":203,"line":1412},45,[201,1414,1415],{"class":222},"    if",[201,1417,1418],{"class":235}," (",[201,1420,1421],{"class":222},"!",[201,1423,1424],{"class":235},"subject ",[201,1426,833],{"class":222},[201,1428,1429],{"class":235}," groupId) ",[201,1431,1125],{"class":222},[201,1433,640],{"class":235},[201,1435,1436],{"class":415},"\u002F\u002F blank row, or already created on a previous run\n",[201,1438,1440],{"class":203,"line":1439},46,[201,1441,422],{"emptyLinePlaceholder":421},[201,1443,1445,1447,1450,1452,1454],{"class":203,"line":1444},47,[201,1446,866],{"class":222},[201,1448,1449],{"class":211}," participants",[201,1451,605],{"class":222},[201,1453,966],{"class":655},[201,1455,1456],{"class":235},"(participantsCell);\n",[201,1458,1460],{"class":203,"line":1459},48,[201,1461,422],{"emptyLinePlaceholder":421},[201,1463,1465,1468],{"class":203,"line":1464},49,[201,1466,1467],{"class":222},"    let",[201,1469,1470],{"class":235}," group;\n",[201,1472,1474,1477],{"class":203,"line":1473},50,[201,1475,1476],{"class":222},"    try",[201,1478,1357],{"class":235},[201,1480,1482,1485,1487,1489,1491,1494,1496,1499,1502,1504,1506],{"class":203,"line":1481},51,[201,1483,1484],{"class":235},"      group ",[201,1486,1389],{"class":222},[201,1488,656],{"class":655},[201,1490,659],{"class":235},[201,1492,1493],{"class":215},"'post'",[201,1495,19],{"class":235},[201,1497,1498],{"class":215},"'\u002Fgroups'",[201,1500,1501],{"class":235},", { subject, description: description ",[201,1503,833],{"class":222},[201,1505,785],{"class":211},[201,1507,1508],{"class":235},", participants });\n",[201,1510,1512,1515,1518],{"class":203,"line":1511},52,[201,1513,1514],{"class":235},"    } ",[201,1516,1517],{"class":222},"catch",[201,1519,1520],{"class":235}," (e) {\n",[201,1522,1524,1527,1529,1532,1535,1537,1540,1542,1545,1547],{"class":203,"line":1523},53,[201,1525,1526],{"class":235},"      sheet.",[201,1528,1286],{"class":655},[201,1530,1531],{"class":235},"(rowNumber, ",[201,1533,1534],{"class":211},"6",[201,1536,995],{"class":235},[201,1538,1539],{"class":655},"setValue",[201,1541,659],{"class":235},[201,1543,1544],{"class":215},"'error: '",[201,1546,728],{"class":222},[201,1548,1549],{"class":235}," e.message);\n",[201,1551,1553,1556,1559,1561,1564],{"class":203,"line":1552},54,[201,1554,1555],{"class":235},"      Utilities.",[201,1557,1558],{"class":655},"sleep",[201,1560,659],{"class":235},[201,1562,1563],{"class":211},"15000",[201,1565,705],{"class":235},[201,1567,1569,1572],{"class":203,"line":1568},55,[201,1570,1571],{"class":222},"      return",[201,1573,611],{"class":235},[201,1575,1577],{"class":203,"line":1576},56,[201,1578,1579],{"class":235},"    }\n",[201,1581,1583],{"class":203,"line":1582},57,[201,1584,1585],{"class":415},"    \u002F\u002F Write the id before anything else can fail: a re-run must never create this group twice.\n",[201,1587,1589,1592,1594,1596,1599,1601,1603],{"class":203,"line":1588},58,[201,1590,1591],{"class":235},"    sheet.",[201,1593,1286],{"class":655},[201,1595,1531],{"class":235},[201,1597,1598],{"class":211},"4",[201,1600,995],{"class":235},[201,1602,1539],{"class":655},[201,1604,1605],{"class":235},"(group.id);\n",[201,1607,1609],{"class":203,"line":1608},59,[201,1610,422],{"emptyLinePlaceholder":421},[201,1612,1614,1616],{"class":203,"line":1613},60,[201,1615,1476],{"class":222},[201,1617,1357],{"class":235},[201,1619,1621,1624,1627,1629,1632,1634,1637],{"class":203,"line":1620},61,[201,1622,1623],{"class":222},"      const",[201,1625,1626],{"class":211}," groupPath",[201,1628,605],{"class":222},[201,1630,1631],{"class":215}," '\u002Fgroups\u002F'",[201,1633,728],{"class":222},[201,1635,1636],{"class":655}," encodeURIComponent",[201,1638,1605],{"class":235},[201,1640,1642,1644,1647,1649,1651,1653,1655,1657,1659,1662],{"class":203,"line":1641},62,[201,1643,1623],{"class":222},[201,1645,1646],{"class":211}," invite",[201,1648,605],{"class":222},[201,1650,656],{"class":655},[201,1652,659],{"class":235},[201,1654,1089],{"class":215},[201,1656,1092],{"class":235},[201,1658,171],{"class":222},[201,1660,1661],{"class":215}," '\u002Finvite'",[201,1663,705],{"class":235},[201,1665,1667,1669,1671,1673,1676,1678,1680],{"class":203,"line":1666},63,[201,1668,1526],{"class":235},[201,1670,1286],{"class":655},[201,1672,1531],{"class":235},[201,1674,1675],{"class":211},"5",[201,1677,995],{"class":235},[201,1679,1539],{"class":655},[201,1681,1682],{"class":235},"(invite.link);\n",[201,1684,1686,1688,1690,1692,1694,1696,1698,1700,1703,1706,1709,1711,1714],{"class":203,"line":1685},64,[201,1687,1526],{"class":235},[201,1689,1286],{"class":655},[201,1691,1531],{"class":235},[201,1693,1318],{"class":211},[201,1695,995],{"class":235},[201,1697,1539],{"class":655},[201,1699,659],{"class":235},[201,1701,1702],{"class":655},"notAdded_",[201,1704,1705],{"class":235},"(groupPath, participants).",[201,1707,1708],{"class":655},"join",[201,1710,659],{"class":235},[201,1712,1713],{"class":215},"', '",[201,1715,933],{"class":235},[201,1717,1719,1722,1724,1726,1728,1731],{"class":203,"line":1718},65,[201,1720,1721],{"class":655},"      wapito_",[201,1723,659],{"class":235},[201,1725,1493],{"class":215},[201,1727,19],{"class":235},[201,1729,1730],{"class":215},"'\u002Fmessages\u002Ftext'",[201,1732,1733],{"class":235},", {\n",[201,1735,1737],{"class":203,"line":1736},66,[201,1738,1739],{"class":235},"        to: group.id,\n",[201,1741,1743,1746,1749,1751,1754,1756,1759,1761,1764,1766,1769],{"class":203,"line":1742},67,[201,1744,1745],{"class":235},"        body: ",[201,1747,1748],{"class":215},"'Welcome to '",[201,1750,728],{"class":222},[201,1752,1753],{"class":235}," subject ",[201,1755,171],{"class":222},[201,1757,1758],{"class":215}," '. '",[201,1760,728],{"class":222},[201,1762,1763],{"class":235}," (description ",[201,1765,833],{"class":222},[201,1767,1768],{"class":215}," 'Say hello!'",[201,1770,1771],{"class":235},"),\n",[201,1773,1775],{"class":203,"line":1774},68,[201,1776,1777],{"class":235},"      });\n",[201,1779,1781,1783,1785,1787,1789,1791,1793,1795,1798],{"class":203,"line":1780},69,[201,1782,1526],{"class":235},[201,1784,1286],{"class":655},[201,1786,1531],{"class":235},[201,1788,1534],{"class":211},[201,1790,995],{"class":235},[201,1792,1539],{"class":655},[201,1794,659],{"class":235},[201,1796,1797],{"class":215},"'created'",[201,1799,705],{"class":235},[201,1801,1803,1805,1807],{"class":203,"line":1802},70,[201,1804,1514],{"class":235},[201,1806,1517],{"class":222},[201,1808,1520],{"class":235},[201,1810,1812,1814,1816,1818,1820,1822,1824,1826,1829,1831],{"class":203,"line":1811},71,[201,1813,1526],{"class":235},[201,1815,1286],{"class":655},[201,1817,1531],{"class":235},[201,1819,1534],{"class":211},[201,1821,995],{"class":235},[201,1823,1539],{"class":655},[201,1825,659],{"class":235},[201,1827,1828],{"class":215},"'created, then: '",[201,1830,728],{"class":222},[201,1832,1549],{"class":235},[201,1834,1836],{"class":203,"line":1835},72,[201,1837,1579],{"class":235},[201,1839,1841],{"class":203,"line":1840},73,[201,1842,422],{"emptyLinePlaceholder":421},[201,1844,1846],{"class":203,"line":1845},74,[201,1847,1848],{"class":415},"    \u002F\u002F The channel's send queue paces messages on its own; the pause here keeps\n",[201,1850,1852],{"class":203,"line":1851},75,[201,1853,1854],{"class":415},"    \u002F\u002F group creation itself unhurried, which is the part WhatsApp watches.\n",[201,1856,1858,1861,1863,1865,1867],{"class":203,"line":1857},76,[201,1859,1860],{"class":235},"    Utilities.",[201,1862,1558],{"class":655},[201,1864,659],{"class":235},[201,1866,1563],{"class":211},[201,1868,705],{"class":235},[201,1870,1872],{"class":203,"line":1871},77,[201,1873,805],{"class":235},[201,1875,1877],{"class":203,"line":1876},78,[201,1878,378],{"class":235},[11,1880,1881,1882,1885,1886,29,1889,1892],{},"Run ",[127,1883,1884],{},"createGroupsFromSheet"," from the editor toolbar. The first run asks you to authorise the\nscript to call external services and edit the sheet — that is ",[127,1887,1888],{},"UrlFetchApp",[127,1890,1891],{},"SpreadsheetApp",", nothing else. Within a minute the D–G columns fill in, and the groups appear on\nthe linked phone.",[11,1894,1895],{},"A few things the script does on purpose:",[140,1897,1898,1904,1918,1939],{},[143,1899,1900,1903],{},[39,1901,1902],{},"It is re-runnable."," The group id is written the moment the group exists, and a row with\nan id is skipped, so a failure on row 12 is fixed by correcting row 12 and running again;\nrows 2–11 are not created twice, and neither is row 12 if only its welcome message failed.",[143,1905,1906,1909,1910,1912,1913,1917],{},[39,1907,1908],{},"It reads the group back instead of trusting the request."," ",[127,1911,1702],{}," fetches the member\nlist once per new group and keeps every number from column C that is not in it. The comparison\nis by phone number, and a member the newer WhatsApp versions list by LID with no phone (see the\n",[15,1914,1916],{"href":1915},"\u002Fblog\u002Fwhatsapp-lids-explained\u002F","LID explainer",") cannot be matched, so when the count is short\na number can land in column G that is in fact in the group; when the count is full, nothing is\ncompared and column G stays empty. Glance at column G before Step 3.",[143,1919,1920,1909,1923,1926,1927,1930,1931,1934,1935,773],{},[39,1921,1922],{},"It writes the error code, not a stack trace.",[127,1924,1925],{},"invalid_recipient {\"to\":\"+1555\"}"," in column F\ntells you which number is malformed; ",[127,1928,1929],{},"created, then: warmup_limit"," tells you the group exists\nbut the welcome was paced; ",[127,1932,1933],{},"channel_not_connected"," means the phone is unlinked. Every code is\ndocumented under ",[15,1936,1938],{"href":1937},"\u002Fdocs\u002Ferrors\u002F","error codes",[143,1940,1941,1944],{},[39,1942,1943],{},"It waits between groups."," Fifteen seconds is not a magic number. It is a reminder that a\nhuman creating groups takes minutes, not milliseconds, and that the group-creation call is the\none to keep slow. The welcome message goes through the channel's send queue regardless.",[43,1946,1948],{"id":1947},"step-3-the-people-who-could-not-be-added","Step 3 — the people who could not be added",[11,1950,1951,1952,1955],{},"Column G holds the people the group does not know about: the numbers WhatsApp declined to add\nwhen the group was created, typically because their privacy settings only let contacts add them\n— the same people the add-participants call would have reported as ",[127,1953,1954],{},"invite_required",". For\nthose, the honest path is to send them the link and let them join. This second function reads\ncolumn G, messages one number at a time, and takes each number off the cell as soon as its\nmessage has gone out, so a run can stop anywhere and the next one picks up what is left:",[192,1957,1959],{"className":580,"code":1958,"language":582,"meta":197,"style":197},"function inviteTheRest() {\n  const sheet = SpreadsheetApp.getActive().getSheetByName(SHEET_NAME);\n  const rows = sheet.getRange(FIRST_ROW, 1, sheet.getLastRow() - FIRST_ROW + 1, 7).getValues();\n\n  for (let i = 0; i \u003C rows.length; i += 1) {\n    const [subject, , , , inviteLink, , notAddedCell] = rows[i];\n    const pending = numbersIn_(notAddedCell);\n    if (!inviteLink || pending.length === 0) continue;\n\n    while (pending.length > 0) {\n      try {\n        wapito_('post', '\u002Fmessages\u002Ftext', {\n          to: pending[0],\n          body: 'You were invited to \"' + subject + '\" on WhatsApp. Join here if you would like to: ' + inviteLink,\n        });\n      } catch (e) {\n        \u002F\u002F Usually cold_send_limit: the guard has spoken for today. Whoever is\n        \u002F\u002F left stays in column G, and the next run starts with them.\n        sheet.getRange(FIRST_ROW + i, 6).setValue('inviting: ' + e.message);\n        return;\n      }\n      pending.shift();\n      sheet.getRange(FIRST_ROW + i, 7).setValue(pending.join(', '));\n      Utilities.sleep(3000);\n    }\n    sheet.getRange(FIRST_ROW + i, 6).setValue('invited');\n  }\n}\n",[127,1960,1961,1970,1992,2036,2040,2078,2105,2119,2149,2153,2170,2177,2192,2203,2225,2230,2239,2244,2249,2280,2287,2292,2302,2333,2346,2350,2377,2381],{"__ignoreMap":197},[201,1962,1963,1965,1968],{"class":203,"line":204},[201,1964,652],{"class":222},[201,1966,1967],{"class":655}," inviteTheRest",[201,1969,1242],{"class":235},[201,1971,1972,1974,1976,1978,1980,1982,1984,1986,1988,1990],{"class":203,"line":226},[201,1973,680],{"class":222},[201,1975,1250],{"class":211},[201,1977,605],{"class":222},[201,1979,1255],{"class":235},[201,1981,1258],{"class":655},[201,1983,694],{"class":235},[201,1985,1263],{"class":655},[201,1987,659],{"class":235},[201,1989,1268],{"class":211},[201,1991,705],{"class":235},[201,1993,1994,1996,1998,2000,2002,2004,2006,2008,2010,2012,2014,2016,2018,2020,2022,2024,2026,2028,2030,2032,2034],{"class":203,"line":244},[201,1995,680],{"class":222},[201,1997,1278],{"class":211},[201,1999,605],{"class":222},[201,2001,1283],{"class":235},[201,2003,1286],{"class":655},[201,2005,659],{"class":235},[201,2007,1291],{"class":211},[201,2009,19],{"class":235},[201,2011,1296],{"class":211},[201,2013,1299],{"class":235},[201,2015,1302],{"class":655},[201,2017,830],{"class":235},[201,2019,1307],{"class":222},[201,2021,632],{"class":211},[201,2023,728],{"class":222},[201,2025,1120],{"class":211},[201,2027,19],{"class":235},[201,2029,1318],{"class":211},[201,2031,995],{"class":235},[201,2033,1323],{"class":655},[201,2035,1326],{"class":235},[201,2037,2038],{"class":203,"line":254},[201,2039,422],{"emptyLinePlaceholder":421},[201,2041,2042,2045,2047,2050,2053,2055,2058,2061,2064,2067,2069,2071,2074,2076],{"class":203,"line":314},[201,2043,2044],{"class":222},"  for",[201,2046,1418],{"class":235},[201,2048,2049],{"class":222},"let",[201,2051,2052],{"class":235}," i ",[201,2054,1389],{"class":222},[201,2056,2057],{"class":211}," 0",[201,2059,2060],{"class":235},"; i ",[201,2062,2063],{"class":222},"\u003C",[201,2065,2066],{"class":235}," rows.",[201,2068,1115],{"class":211},[201,2070,2060],{"class":235},[201,2072,2073],{"class":222},"+=",[201,2075,1120],{"class":211},[201,2077,675],{"class":235},[201,2079,2080,2082,2084,2086,2089,2092,2095,2098,2100,2102],{"class":203,"line":327},[201,2081,866],{"class":222},[201,2083,1365],{"class":235},[201,2085,1368],{"class":211},[201,2087,2088],{"class":235},", , , , ",[201,2090,2091],{"class":211},"inviteLink",[201,2093,2094],{"class":235},", , ",[201,2096,2097],{"class":211},"notAddedCell",[201,2099,1386],{"class":235},[201,2101,1389],{"class":222},[201,2103,2104],{"class":235}," rows[i];\n",[201,2106,2107,2109,2112,2114,2116],{"class":203,"line":375},[201,2108,866],{"class":222},[201,2110,2111],{"class":211}," pending",[201,2113,605],{"class":222},[201,2115,966],{"class":655},[201,2117,2118],{"class":235},"(notAddedCell);\n",[201,2120,2121,2123,2125,2127,2130,2132,2135,2137,2140,2142,2144,2147],{"class":203,"line":449},[201,2122,1415],{"class":222},[201,2124,1418],{"class":235},[201,2126,1421],{"class":222},[201,2128,2129],{"class":235},"inviteLink ",[201,2131,833],{"class":222},[201,2133,2134],{"class":235}," pending.",[201,2136,1115],{"class":211},[201,2138,2139],{"class":222}," ===",[201,2141,2057],{"class":211},[201,2143,1006],{"class":235},[201,2145,2146],{"class":222},"continue",[201,2148,611],{"class":235},[201,2150,2151],{"class":203,"line":454},[201,2152,422],{"emptyLinePlaceholder":421},[201,2154,2155,2158,2161,2163,2166,2168],{"class":203,"line":467},[201,2156,2157],{"class":222},"    while",[201,2159,2160],{"class":235}," (pending.",[201,2162,1115],{"class":211},[201,2164,2165],{"class":222}," >",[201,2167,2057],{"class":211},[201,2169,675],{"class":235},[201,2171,2172,2175],{"class":203,"line":485},[201,2173,2174],{"class":222},"      try",[201,2176,1357],{"class":235},[201,2178,2179,2182,2184,2186,2188,2190],{"class":203,"line":493},[201,2180,2181],{"class":655},"        wapito_",[201,2183,659],{"class":235},[201,2185,1493],{"class":215},[201,2187,19],{"class":235},[201,2189,1730],{"class":215},[201,2191,1733],{"class":235},[201,2193,2194,2197,2200],{"class":203,"line":499},[201,2195,2196],{"class":235},"          to: pending[",[201,2198,2199],{"class":211},"0",[201,2201,2202],{"class":235},"],\n",[201,2204,2205,2208,2211,2213,2215,2217,2220,2222],{"class":203,"line":504},[201,2206,2207],{"class":235},"          body: ",[201,2209,2210],{"class":215},"'You were invited to \"'",[201,2212,728],{"class":222},[201,2214,1753],{"class":235},[201,2216,171],{"class":222},[201,2218,2219],{"class":215}," '\" on WhatsApp. Join here if you would like to: '",[201,2221,728],{"class":222},[201,2223,2224],{"class":235}," inviteLink,\n",[201,2226,2227],{"class":203,"line":518},[201,2228,2229],{"class":235},"        });\n",[201,2231,2232,2235,2237],{"class":203,"line":535},[201,2233,2234],{"class":235},"      } ",[201,2236,1517],{"class":222},[201,2238,1520],{"class":235},[201,2240,2241],{"class":203,"line":841},[201,2242,2243],{"class":415},"        \u002F\u002F Usually cold_send_limit: the guard has spoken for today. Whoever is\n",[201,2245,2246],{"class":203,"line":863},[201,2247,2248],{"class":415},"        \u002F\u002F left stays in column G, and the next run starts with them.\n",[201,2250,2251,2254,2256,2258,2260,2262,2265,2267,2269,2271,2273,2276,2278],{"class":203,"line":882},[201,2252,2253],{"class":235},"        sheet.",[201,2255,1286],{"class":655},[201,2257,659],{"class":235},[201,2259,1291],{"class":211},[201,2261,728],{"class":222},[201,2263,2264],{"class":235}," i, ",[201,2266,1534],{"class":211},[201,2268,995],{"class":235},[201,2270,1539],{"class":655},[201,2272,659],{"class":235},[201,2274,2275],{"class":215},"'inviting: '",[201,2277,728],{"class":222},[201,2279,1549],{"class":235},[201,2281,2282,2285],{"class":203,"line":936},[201,2283,2284],{"class":222},"        return",[201,2286,611],{"class":235},[201,2288,2289],{"class":203,"line":942},[201,2290,2291],{"class":235},"      }\n",[201,2293,2294,2297,2300],{"class":203,"line":951},[201,2295,2296],{"class":235},"      pending.",[201,2298,2299],{"class":655},"shift",[201,2301,1326],{"class":235},[201,2303,2304,2306,2308,2310,2312,2314,2316,2318,2320,2322,2325,2327,2329,2331],{"class":203,"line":956},[201,2305,1526],{"class":235},[201,2307,1286],{"class":655},[201,2309,659],{"class":235},[201,2311,1291],{"class":211},[201,2313,728],{"class":222},[201,2315,2264],{"class":235},[201,2317,1318],{"class":211},[201,2319,995],{"class":235},[201,2321,1539],{"class":655},[201,2323,2324],{"class":235},"(pending.",[201,2326,1708],{"class":655},[201,2328,659],{"class":235},[201,2330,1713],{"class":215},[201,2332,933],{"class":235},[201,2334,2335,2337,2339,2341,2344],{"class":203,"line":961},[201,2336,1555],{"class":235},[201,2338,1558],{"class":655},[201,2340,659],{"class":235},[201,2342,2343],{"class":211},"3000",[201,2345,705],{"class":235},[201,2347,2348],{"class":203,"line":976},[201,2349,1579],{"class":235},[201,2351,2352,2354,2356,2358,2360,2362,2364,2366,2368,2370,2372,2375],{"class":203,"line":1027},[201,2353,1591],{"class":235},[201,2355,1286],{"class":655},[201,2357,659],{"class":235},[201,2359,1291],{"class":211},[201,2361,728],{"class":222},[201,2363,2264],{"class":235},[201,2365,1534],{"class":211},[201,2367,995],{"class":235},[201,2369,1539],{"class":655},[201,2371,659],{"class":235},[201,2373,2374],{"class":215},"'invited'",[201,2376,705],{"class":235},[201,2378,2379],{"class":203,"line":1032},[201,2380,939],{"class":235},[201,2382,2383],{"class":203,"line":1037},[201,2384,378],{"class":235},[11,2386,2387,2388,2390,2391,2394,2395,2398,2399,2402,2403,2406],{},"Run it after ",[127,2389,1884],{},", once you have looked at column G; column F reads ",[127,2392,2393],{},"invited","\nonce a row's list is empty. Each of those messages is a ",[39,2396,2397],{},"cold send"," if the person has never\nwritten to your number, and the cold-send guard caps how many you can start an hour (ten on a\nnumber's first two days). If the list is long, the guard will answer ",[127,2400,2401],{},"429 cold_send_limit","; that\nis the platform doing its job. The function then writes ",[127,2404,2405],{},"inviting: cold_send_limit"," to column F\nand stops, with the unsent numbers still in column G, and the fix is to run it again tomorrow,\nnot to remove the pause. Better still, put the link where the people already are — the\nconfirmation e-mail, the receipt, the class portal — and let them come to the group.",[43,2408,2410],{"id":2409},"variant-add-new-rows-to-one-existing-group","Variant: add new rows to one existing group",[11,2412,2413],{},"The other common shape is a single group — this month's cohort, the volunteers, the delivery\ndrivers — that new sign-ups should be added to as rows appear. Same helper, different loop:",[192,2415,2417],{"className":580,"code":2416,"language":582,"meta":197,"style":197},"const GROUP_ID = '120363041234567890@g.us'; \u002F\u002F from column D, or the group's info in the dashboard\n\nfunction addNewRowsToGroup() {\n  const sheet = SpreadsheetApp.getActive().getSheetByName('Signups'); \u002F\u002F A phone · B added\n  const rows = sheet.getRange(2, 1, sheet.getLastRow() - 1, 2).getValues();\n  const pending = rows.map((r, i) => ({ phone: String(r[0]).trim(), row: i + 2, done: r[1] })).filter((r) => r.phone && !r.done);\n\n  \u002F\u002F Up to fifty per call; keep batches small anyway.\n  for (let start = 0; start \u003C pending.length; start += 10) {\n    const batch = pending.slice(start, start + 10);\n    const { results } = wapito_('post', '\u002Fgroups\u002F' + encodeURIComponent(GROUP_ID) + '\u002Fparticipants', {\n      participants: batch.map((r) => r.phone),\n    });\n    results.forEach((result, i) => sheet.getRange(batch[i].row, 2).setValue(result.status));\n    Utilities.sleep(30000);\n  }\n}\n",[127,2418,2419,2436,2440,2449,2476,2517,2594,2598,2603,2636,2659,2702,2720,2725,2761,2774,2778],{"__ignoreMap":197},[201,2420,2421,2423,2426,2428,2431,2433],{"class":203,"line":204},[201,2422,599],{"class":222},[201,2424,2425],{"class":211}," GROUP_ID",[201,2427,605],{"class":222},[201,2429,2430],{"class":215}," '120363041234567890@g.us'",[201,2432,640],{"class":235},[201,2434,2435],{"class":415},"\u002F\u002F from column D, or the group's info in the dashboard\n",[201,2437,2438],{"class":203,"line":226},[201,2439,422],{"emptyLinePlaceholder":421},[201,2441,2442,2444,2447],{"class":203,"line":244},[201,2443,652],{"class":222},[201,2445,2446],{"class":655}," addNewRowsToGroup",[201,2448,1242],{"class":235},[201,2450,2451,2453,2455,2457,2459,2461,2463,2465,2467,2470,2473],{"class":203,"line":254},[201,2452,680],{"class":222},[201,2454,1250],{"class":211},[201,2456,605],{"class":222},[201,2458,1255],{"class":235},[201,2460,1258],{"class":655},[201,2462,694],{"class":235},[201,2464,1263],{"class":655},[201,2466,659],{"class":235},[201,2468,2469],{"class":215},"'Signups'",[201,2471,2472],{"class":235},"); ",[201,2474,2475],{"class":415},"\u002F\u002F A phone · B added\n",[201,2477,2478,2480,2482,2484,2486,2488,2490,2493,2495,2497,2499,2501,2503,2505,2507,2509,2511,2513,2515],{"class":203,"line":314},[201,2479,680],{"class":222},[201,2481,1278],{"class":211},[201,2483,605],{"class":222},[201,2485,1283],{"class":235},[201,2487,1286],{"class":655},[201,2489,659],{"class":235},[201,2491,2492],{"class":211},"2",[201,2494,19],{"class":235},[201,2496,1296],{"class":211},[201,2498,1299],{"class":235},[201,2500,1302],{"class":655},[201,2502,830],{"class":235},[201,2504,1307],{"class":222},[201,2506,1120],{"class":211},[201,2508,19],{"class":235},[201,2510,2492],{"class":211},[201,2512,995],{"class":235},[201,2514,1323],{"class":655},[201,2516,1326],{"class":235},[201,2518,2519,2521,2523,2525,2527,2529,2531,2534,2536,2538,2540,2542,2545,2548,2551,2553,2556,2558,2561,2563,2565,2568,2570,2573,2575,2577,2579,2581,2583,2586,2589,2591],{"class":203,"line":327},[201,2520,680],{"class":222},[201,2522,2111],{"class":211},[201,2524,605],{"class":222},[201,2526,2066],{"class":235},[201,2528,998],{"class":655},[201,2530,1001],{"class":235},[201,2532,2533],{"class":207},"r",[201,2535,19],{"class":235},[201,2537,1350],{"class":207},[201,2539,1006],{"class":235},[201,2541,1009],{"class":222},[201,2543,2544],{"class":235}," ({ phone: ",[201,2546,2547],{"class":655},"String",[201,2549,2550],{"class":235},"(r[",[201,2552,2199],{"class":211},[201,2554,2555],{"class":235},"]).",[201,2557,1015],{"class":655},[201,2559,2560],{"class":235},"(), row: i ",[201,2562,171],{"class":222},[201,2564,637],{"class":211},[201,2566,2567],{"class":235},", done: r[",[201,2569,1296],{"class":211},[201,2571,2572],{"class":235},"] })).",[201,2574,1021],{"class":655},[201,2576,1001],{"class":235},[201,2578,2533],{"class":207},[201,2580,1006],{"class":235},[201,2582,1009],{"class":222},[201,2584,2585],{"class":235}," r.phone ",[201,2587,2588],{"class":222},"&&",[201,2590,1188],{"class":222},[201,2592,2593],{"class":235},"r.done);\n",[201,2595,2596],{"class":203,"line":375},[201,2597,422],{"emptyLinePlaceholder":421},[201,2599,2600],{"class":203,"line":449},[201,2601,2602],{"class":415},"  \u002F\u002F Up to fifty per call; keep batches small anyway.\n",[201,2604,2605,2607,2609,2611,2614,2616,2618,2621,2623,2625,2627,2629,2631,2634],{"class":203,"line":454},[201,2606,2044],{"class":222},[201,2608,1418],{"class":235},[201,2610,2049],{"class":222},[201,2612,2613],{"class":235}," start ",[201,2615,1389],{"class":222},[201,2617,2057],{"class":211},[201,2619,2620],{"class":235},"; start ",[201,2622,2063],{"class":222},[201,2624,2134],{"class":235},[201,2626,1115],{"class":211},[201,2628,2620],{"class":235},[201,2630,2073],{"class":222},[201,2632,2633],{"class":211}," 10",[201,2635,675],{"class":235},[201,2637,2638,2640,2643,2645,2647,2650,2653,2655,2657],{"class":203,"line":467},[201,2639,866],{"class":222},[201,2641,2642],{"class":211}," batch",[201,2644,605],{"class":222},[201,2646,2134],{"class":235},[201,2648,2649],{"class":655},"slice",[201,2651,2652],{"class":235},"(start, start ",[201,2654,171],{"class":222},[201,2656,2633],{"class":211},[201,2658,705],{"class":235},[201,2660,2661,2663,2666,2669,2672,2674,2676,2678,2680,2682,2685,2687,2689,2691,2694,2696,2698,2700],{"class":203,"line":485},[201,2662,866],{"class":222},[201,2664,2665],{"class":235}," { ",[201,2667,2668],{"class":211},"results",[201,2670,2671],{"class":235}," } ",[201,2673,1389],{"class":222},[201,2675,656],{"class":655},[201,2677,659],{"class":235},[201,2679,1493],{"class":215},[201,2681,19],{"class":235},[201,2683,2684],{"class":215},"'\u002Fgroups\u002F'",[201,2686,728],{"class":222},[201,2688,1636],{"class":655},[201,2690,659],{"class":235},[201,2692,2693],{"class":211},"GROUP_ID",[201,2695,1006],{"class":235},[201,2697,171],{"class":222},[201,2699,1097],{"class":215},[201,2701,1733],{"class":235},[201,2703,2704,2707,2709,2711,2713,2715,2717],{"class":203,"line":493},[201,2705,2706],{"class":235},"      participants: batch.",[201,2708,998],{"class":655},[201,2710,1001],{"class":235},[201,2712,2533],{"class":207},[201,2714,1006],{"class":235},[201,2716,1009],{"class":222},[201,2718,2719],{"class":235}," r.phone),\n",[201,2721,2722],{"class":203,"line":499},[201,2723,2724],{"class":235},"    });\n",[201,2726,2727,2730,2732,2734,2737,2739,2741,2743,2745,2747,2749,2752,2754,2756,2758],{"class":203,"line":504},[201,2728,2729],{"class":235},"    results.",[201,2731,1340],{"class":655},[201,2733,1001],{"class":235},[201,2735,2736],{"class":207},"result",[201,2738,19],{"class":235},[201,2740,1350],{"class":207},[201,2742,1006],{"class":235},[201,2744,1009],{"class":222},[201,2746,1283],{"class":235},[201,2748,1286],{"class":655},[201,2750,2751],{"class":235},"(batch[i].row, ",[201,2753,2492],{"class":211},[201,2755,995],{"class":235},[201,2757,1539],{"class":655},[201,2759,2760],{"class":235},"(result.status));\n",[201,2762,2763,2765,2767,2769,2772],{"class":203,"line":518},[201,2764,1860],{"class":235},[201,2766,1558],{"class":655},[201,2768,659],{"class":235},[201,2770,2771],{"class":211},"30000",[201,2773,705],{"class":235},[201,2775,2776],{"class":203,"line":535},[201,2777,939],{"class":235},[201,2779,2780],{"class":203,"line":841},[201,2781,378],{"class":235},[11,2783,2784,2785,2788,2789,2791,2792,2794,2795,2797,2798,2800],{},"Attach it to a time-driven trigger (",[39,2786,2787],{},"Triggers → Add trigger → every hour",") and the sheet\nbecomes a queue. The status column fills with ",[127,2790,550],{}," or ",[127,2793,1954],{},", and the group's\nparticipant list — ",[127,2796,558],{}," — is the source of truth if the two ever\ndisagree. Newer WhatsApp versions may list a member by LID with no phone number; the\n",[15,2799,1916],{"href":1915}," covers what to do with those.",[43,2802,2804],{"id":2803},"the-same-flow-in-n8n","The same flow in n8n",[11,2806,2807],{},"If code is not the team's language, the calls map onto HTTP Request nodes:",[2809,2810,2811,2826,2843,2850,2862],"ol",{},[143,2812,2813,2814,2817,2818,2822,2823,773],{},"A ",[39,2815,2816],{},"Google Sheets"," trigger or ",[2819,2820,2821],"em",{},"Read rows"," node, filtered to rows with an empty ",[2819,2824,2825],{},"Group id",[143,2827,2828,2831,2832,2835,2836,2839,2840,773],{},[39,2829,2830],{},"HTTP Request"," — ",[127,2833,2834],{},"POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups",", JSON body from the row's columns,\n",[2819,2837,2838],{},"Header Auth"," credential holding ",[127,2841,2842],{},"Authorization: Bearer wpt_…",[143,2844,2845,2831,2847,773],{},[39,2846,2830],{},[127,2848,2849],{},"GET https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F{{ $json.id }}\u002Finvite",[143,2851,2852,2831,2854,2857,2858,2861],{},[39,2853,2830],{},[127,2855,2856],{},"POST https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fmessages\u002Ftext"," with ",[127,2859,2860],{},"to"," set to the group\nid and the welcome text.",[143,2863,2813,2864,1909,2866,2869],{},[39,2865,2816],{},[2819,2867,2868],{},"Update row"," node writing id, link and status back.",[11,2871,2872,2873,2876,2877,2879,2880,2883,2884,2887,2888,2891],{},"To fill a ",[2819,2874,2875],{},"Not added"," column as the script does, add a fourth ",[39,2878,2830],{}," —\n",[127,2881,2882],{},"GET https:\u002F\u002Fapi.wapito.com\u002Fv1\u002Fgroups\u002F{{ $json.id }}\u002Fparticipants"," — after step 3 and a small\n",[39,2885,2886],{},"Code"," node that keeps the row's numbers whose digits are not among the returned ",[127,2889,2890],{},"phone"," values.",[11,2893,2894,2895,2898,2899,2902,2903,2906,2907,2910,2911,2915],{},"Put a ",[39,2896,2897],{},"Wait"," node of fifteen to thirty seconds between iterations, and turn on ",[2819,2900,2901],{},"Retry on fail","\nonly for the ",[127,2904,2905],{},"rate_limited"," status: every other ",[127,2908,2909],{},"4xx"," on these calls is a fact about the data,\nnot a transient. The ",[15,2912,2914],{"href":2913},"\u002Fintegrations\u002Fn8n\u002F","n8n integration page"," has the credential setup and a\nreceiving workflow for the group events.",[43,2917,2919],{"id":2918},"when-a-row-says-error","When a row says \"error\"",[11,2921,2922],{},"Column F is where the API tells you what it did not like. The codes you will actually see, and\nwhat each one means for the row:",[51,2924,2925,2938],{},[54,2926,2927],{},[57,2928,2929,2932,2935],{},[60,2930,2931],{},"Column F",[60,2933,2934],{},"What happened",[60,2936,2937],{},"What to do",[82,2939,2940,2952,2964,2976,2994,3006,3019],{},[57,2941,2942,2946,2949],{},[87,2943,2944],{},[127,2945,1925],{},[87,2947,2948],{},"A participant is not a dialable number.",[87,2950,2951],{},"Fix the number in column C; the API checks the format before anything is sent.",[57,2953,2954,2958,2961],{},[87,2955,2956],{},[127,2957,1933],{},[87,2959,2960],{},"The phone is unlinked or the session is restarting.",[87,2962,2963],{},"Open the Connect tab, re-link if needed, run again. Nothing was created.",[57,2965,2966,2970,2973],{},[87,2967,2968],{},[127,2969,1929],{},[87,2971,2972],{},"The welcome message tripped a pacing control.",[87,2974,2975],{},"The group exists — column D is filled — but the message was refused. Send it by hand from the phone or with curl and the id in column D; the script skips every row that has an id, so it will not.",[57,2977,2978,2982,2988],{},[87,2979,2980],{},[127,2981,2405],{},[87,2983,2984,2987],{},[127,2985,2986],{},"inviteTheRest"," hit the cold-send guard.",[87,2989,2990,2991,2993],{},"Nothing is wrong. Column G still lists who has not been messaged; run ",[127,2992,2986],{}," again tomorrow. Any other code here names a number in column G the API would not accept — fix or remove it and run again.",[57,2995,2996,3000,3003],{},[87,2997,2998],{},[127,2999,2905],{},[87,3001,3002],{},"More than sixty requests in a minute on Sandbox.",[87,3004,3005],{},"Raise the sleep, or run fewer rows per execution.",[57,3007,3008,3013,3016],{},[87,3009,3010],{},[127,3011,3012],{},"forbidden",[87,3014,3015],{},"The linked number is not an admin of the group.",[87,3017,3018],{},"Only on the add-participants variant: someone demoted the number. Promote it from the phone.",[57,3020,3021,3026,3029],{},[87,3022,3023],{},[127,3024,3025],{},"not_found",[87,3027,3028],{},"The group id in column D no longer exists.",[87,3030,3031],{},"The group was deleted from the phone, or the number left it. Clear D and E to recreate it.",[11,3033,3034,3035,3037,3038,3041,3042,3044,3045,3048,3049,3053],{},"Two of these are worth a second look. ",[127,3036,1929],{}," means the ",[2819,3039,3040],{},"messages"," are the\nproblem, not the groups: the number is on its first days and the daily rung is spent. The groups\nexist, the members are in, and the welcome can wait until tomorrow — do not loop on the error. And ",[127,3043,2905],{}," is the one code where a retry is correct; the ",[127,3046,3047],{},"Retry-After","\nheader on the response says how many seconds to wait, and the ",[15,3050,3052],{"href":3051},"\u002Fdocs\u002Frate-limits\u002F","rate-limits guide","\nshows the pattern. Apps Script's six-minute execution limit is the other clock to watch: a sheet\nwith more than about twenty rows should be run in slices, which the \"skip rows that have a group\nid\" rule already makes safe.",[43,3055,3057],{"id":3056},"keeping-it-out-of-trouble","Keeping it out of trouble",[11,3059,3060],{},"Groups are where WhatsApp's judgement is harshest, and a script makes it very easy to do the\nwrong thing quickly. The rules that keep this integration alive:",[140,3062,3063,3069,3075,3085,3098],{},[143,3064,3065,3068],{},[39,3066,3067],{},"Consent before addition."," People who did not agree to be added report groups, and reports\nban numbers. When in doubt, send the invite link and let them choose.",[143,3070,3071,3074],{},[39,3072,3073],{},"Small batches, real gaps."," A few groups an hour from a warmed-up number; a few dozen\nadditions an hour at most. The sleeps in the script are the floor, not the ceiling.",[143,3076,3077,3080,3081,3084],{},[39,3078,3079],{},"Membership approval for public links."," If the invite link goes anywhere public, turn on\n",[127,3082,3083],{},"membership_approval"," in the group settings so a leaked link does not fill the group with\nstrangers.",[143,3086,3087,1909,3090,3093,3094,3097],{},[39,3088,3089],{},"Subscribe to the group events.",[127,3091,3092],{},"groups.participants"," tells you who joined, left or was\nremoved, and ",[127,3095,3096],{},"channel"," tells you the moment the number is timelocked or banned; the script\ncannot see either, your webhook can.",[143,3099,3100,3103],{},[39,3101,3102],{},"Keep a human admin."," The linked number is the group's owner. Promote a person as well, so\nthe group survives a number change.",[11,3105,3106],{},"Everything above is a linked-number API doing what the official one cannot, and the price of that\nis the responsibility to use it the way a person would: create the groups people asked for,\ninvite the ones who did not ask, and never faster than you could by hand.",[3108,3109,3110],"style",{},"html pre.shiki code .sTDnQ, html code.shiki .sTDnQ{--shiki-default:#953800;--shiki-dark:#FFA657}html pre.shiki code .sHrmB, html code.shiki .sHrmB{--shiki-default:#0550AE;--shiki-dark:#79C0FF}html pre.shiki code .sSVrQ, html code.shiki .sSVrQ{--shiki-default:#0A3069;--shiki-dark:#A5D6FF}html pre.shiki code .sjeE4, html code.shiki .sjeE4{--shiki-default:#CF222E;--shiki-dark:#FF7B72}html pre.shiki code .s4rv2, html code.shiki .s4rv2{--shiki-default:#1F2328;--shiki-dark:#E6EDF3}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 .sjgCt, html code.shiki .sjgCt{--shiki-default:#116329;--shiki-dark:#7EE787}html pre.shiki code .sU953, html code.shiki .sU953{--shiki-default:#6E7781;--shiki-dark:#8B949E}html pre.shiki code .sbjLL, html code.shiki .sbjLL{--shiki-default:#8250DF;--shiki-dark:#D2A8FF}",{"title":197,"searchDepth":226,"depth":226,"links":3112},[3113,3114,3115,3116,3117,3118,3119,3120,3121],{"id":45,"depth":226,"text":46},{"id":137,"depth":226,"text":138},{"id":182,"depth":226,"text":183},{"id":562,"depth":226,"text":563},{"id":1947,"depth":226,"text":1948},{"id":2409,"depth":226,"text":2410},{"id":2803,"depth":226,"text":2804},{"id":2918,"depth":226,"text":2919},{"id":3056,"depth":226,"text":3057},"2026-09-15","A step-by-step Apps Script build: read a sheet of customers, create one group per row, publish the invite link, and write the results back.","md",[3126,3127,3128,3129],"create-group","group-participants","group-invite-link","send-group-message",{},"\u002Fblog\u002Fcreate-whatsapp-groups-from-google-sheets",{"title":5,"description":3123},"blog\u002Fcreate-whatsapp-groups-from-google-sheets",[3135,3136,3137],"tutorial","groups","no-code",null,"RyVdq0k3B35fPQAk5J4b9DMGWhXciDuyZidBaR7n2hk",1790464894221]