[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fbulk-api-calls-what-the-docs-skip-before-you-push-volume":156,"\u002Fblog\u002Fbulk-api-calls-what-the-docs-skip-before-you-push-volume-surround":472},[4,23,41,60,78,90,108,137],{"title":5,"path":6,"stem":7,"children":8,"icon":22},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started\u002F1.index",[9,12,17],{"title":10,"path":6,"stem":7,"icon":11},"Introduction","i-lucide-house",{"title":13,"path":14,"stem":15,"icon":16},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F1.getting-started\u002F2.quick-start","i-lucide-zap",{"title":18,"path":19,"stem":20,"icon":21},"Connect WhatsApp Phone Numbers","\u002Fdocs\u002Fgetting-started\u002Fconnect-whatsapp","docs\u002F1.getting-started\u002F3.connect-whatsapp","i-lucide-phone","i-lucide-rocket",{"title":24,"path":25,"stem":26,"children":27,"icon":30},"Team Inbox","\u002Fdocs\u002Finbox","docs\u002F2.inbox\u002F1.index",[28,31,36],{"title":29,"path":25,"stem":26,"icon":30},"Shared Inbox","i-lucide-inbox",{"title":32,"path":33,"stem":34,"icon":35},"Rich Messaging","\u002Fdocs\u002Finbox\u002Frich-messaging","docs\u002F2.inbox\u002F2.rich-messaging","i-lucide-message-square",{"title":37,"path":38,"stem":39,"icon":40},"Contact Details","\u002Fdocs\u002Finbox\u002Fcontact-details","docs\u002F2.inbox\u002F3.contact-details","i-lucide-user-check",{"title":42,"path":43,"stem":44,"children":45,"icon":59},"Messaging","\u002Fdocs\u002Fmessaging","docs\u002F3.messaging\u002F1.index",[46,49,54],{"title":47,"path":43,"stem":44,"icon":48},"Single Message","i-lucide-send",{"title":50,"path":51,"stem":52,"icon":53},"Broadcast","\u002Fdocs\u002Fmessaging\u002Fbroadcast-campaigns","docs\u002F3.messaging\u002F2.broadcast-campaigns","i-lucide-megaphone",{"title":55,"path":56,"stem":57,"icon":58},"Campaign History","\u002Fdocs\u002Fmessaging\u002Fcampaign-history","docs\u002F3.messaging\u002F3.campaign-history","i-lucide-bar-chart","i-lucide-message-circle",{"title":61,"path":62,"stem":63,"children":64,"icon":77},"Contacts","\u002Fdocs\u002Fcontacts","docs\u002F4.contacts\u002F1.index",[65,67,72],{"title":10,"path":62,"stem":63,"icon":66},"i-lucide-book-user",{"title":68,"path":69,"stem":70,"icon":71},"Contact Lists","\u002Fdocs\u002Fcontacts\u002Flists-segmentation","docs\u002F4.contacts\u002F2.lists-segmentation","i-lucide-list-filter",{"title":73,"path":74,"stem":75,"icon":76},"Bulk Import","\u002Fdocs\u002Fcontacts\u002Fimporting-contacts","docs\u002F4.contacts\u002F3.importing-contacts","i-lucide-file-spreadsheet","i-lucide-users",{"title":79,"path":80,"stem":81,"children":82,"icon":84},"Templates","\u002Fdocs\u002Ftemplates","docs\u002F5.templates\u002F1.index",[83,85],{"title":10,"path":80,"stem":81,"icon":84},"i-lucide-file-text",{"title":86,"path":87,"stem":88,"icon":89},"Template Syncing","\u002Fdocs\u002Ftemplates\u002Fsyncing-managing-templates","docs\u002F5.templates\u002F2.syncing-managing-templates","i-lucide-refresh-cw",{"title":91,"path":92,"stem":93,"children":94,"icon":97},"AI Chatbots","\u002Fdocs\u002Fai-chatbots","docs\u002F6.ai-chatbots\u002F1.index",[95,98,103],{"title":96,"path":92,"stem":93,"icon":97},"WhatsBox Bots","i-lucide-bot",{"title":99,"path":100,"stem":101,"icon":102},"Tools","\u002Fdocs\u002Fai-chatbots\u002Ftools","docs\u002F6.ai-chatbots\u002F2.tools","i-lucide-wrench",{"title":104,"path":105,"stem":106,"icon":107},"MS Copilot Studio","\u002Fdocs\u002Fai-chatbots\u002Fcopilot-studio","docs\u002F6.ai-chatbots\u002F3.copilot-studio","i-lucide-cpu",{"title":109,"path":110,"stem":111,"children":112,"icon":136},"Integrations","\u002Fdocs\u002Fintegrations","docs\u002F7.integrations\u002F1.index",[113,116,121,126,131],{"title":114,"path":110,"stem":111,"icon":115},"Developer API","i-lucide-code",{"title":117,"path":118,"stem":119,"icon":120},"Google Sheets","\u002Fdocs\u002Fintegrations\u002Fgoogle-sheets","docs\u002F7.integrations\u002F2.google-sheets","i-lucide-sheet",{"title":122,"path":123,"stem":124,"icon":125},"Firebase Extension","\u002Fdocs\u002Fintegrations\u002Ffirebase-ext","docs\u002F7.integrations\u002F3.firebase-ext","i-lucide-flame",{"title":127,"path":128,"stem":129,"icon":130},"Slack","\u002Fdocs\u002Fintegrations\u002Fslack","docs\u002F7.integrations\u002F4.slack","i-lucide-slack",{"title":132,"path":133,"stem":134,"icon":135},"Zapier","\u002Fdocs\u002Fintegrations\u002Fzapier","docs\u002F7.integrations\u002F5.zapier","i-lucide-blocks","i-lucide-plug",{"title":138,"path":139,"stem":140,"children":141,"icon":155},"Settings & Billing","\u002Fdocs\u002Fsettings","docs\u002F8.settings\u002F1.index",[142,145,150],{"title":143,"path":139,"stem":140,"icon":144},"Team Members","i-lucide-users-round",{"title":146,"path":147,"stem":148,"icon":149},"Miscellaneous","\u002Fdocs\u002Fsettings\u002Faccount-settings","docs\u002F8.settings\u002F2.account-settings","i-lucide-building",{"title":151,"path":152,"stem":153,"icon":154},"Billing","\u002Fdocs\u002Fsettings\u002Fbilling-usage","docs\u002F8.settings\u002F3.billing-usage","i-lucide-credit-card","i-lucide-settings",{"id":157,"title":158,"authors":159,"badge":164,"body":166,"date":459,"description":460,"draft":461,"extension":462,"image":463,"meta":464,"navigation":465,"path":466,"schemaOrg":467,"seo":468,"sitemap":469,"stem":470,"__hash__":471},"posts\u002Fblog\u002Fbulk-api-calls-what-the-docs-skip-before-you-push-volume.md","Bulk API Calls: What the Docs Skip Before You Push Volume",[160],{"name":161,"avatar":162},"WhatsBox Team",{"text":163},"WB",{"label":165},"Bulk api calls",{"type":167,"value":168,"toc":446},"minimark",[169,177,184,187,192,203,206,217,228,235,274,285,289,292,311,314,318,321,327,333,339,342,346,349,352,361,369,373,376,387,400,404,409,412,416,419,423,426,430,433,436,442],[170,171,172,176],"p",{},[173,174,175],"strong",{},"A bulk API call is one HTTP request that carries many records instead of one."," That is the whole definition, and it is also where most teams stop reading the docs and start guessing. The wrapper you put around that single call, not the endpoint itself, decides whether your sync survives ten thousand records or dies at four hundred.",[170,178,179],{},[180,181],"img",{"alt":182,"src":183},"cover","https:\u002F\u002Fstatic.whatsbox.io\u002Fblog-images\u002Fwhatsbox\u002Fai-1549283522-6a0793b662e08edf0d2df984.webp",[170,185,186],{},"Most write-ups explain the endpoint and skip the wrapper. We are going to spend this page on the wrapper.",[188,189,191],"h2",{"id":190},"the-shape-of-a-bulk-call-in-code","The Shape of a Bulk Call, in Code",[170,193,194,195,202],{},"A bulk endpoint accepts a payload of records, hands back a job handle, and lets you poll. Salesforce's own documentation describes its two Bulk APIs of the same family this way: \"Both Salesforce Bulk APIs are based on REST principles and are optimized for working with large sets of data\" (",[196,197,201],"a",{"href":198,"rel":199},"https:\u002F\u002Fdeveloper.salesforce.com\u002Fdocs\u002Fplatform\u002Fapi-asynch\u002Fguide\u002Fasynch-api-intro.html",[200],"nofollow","Salesforce Bulk API introduction","). That sentence carries the design intent. REST plus scale, which in practice means the request does not return your results, it returns a receipt.",[170,204,205],{},"Here is the shape of that interaction, endpoint agnostic:",[207,208,213],"pre",{"className":209,"code":211,"language":212},[210],"language-text","POST \u002Fservices\u002Fdata\u002FvXX.X\u002Fjobs\u002Fingest\nContent-Type: application\u002Fjson\nAccept: application\u002Fjson\n\n{\n \"object\": \"\u003Cyour-object>\",\n \"operation\": \"insert\",\n \"contentType\": \"CSV\",\n \"lineEnding\": \"LF\"\n}\n","text",[214,215,211],"code",{"__ignoreMap":216},"",[170,218,219,220,223,224,227],{},"Two parts matter. The ",[214,221,222],{},"object"," and ",[214,225,226],{},"operation"," fields tell the platform what to do with the data before you have sent any of it. The response gives you back a job identifier, and every subsequent request references that identifier rather than the payload. Your records travel separately, as CSV or JSON, against that job.",[170,229,230,231,234],{},"Apex changes the vocabulary but not the principle. The ",[214,232,233],{},"bulk api apex example"," every developer eventually writes looks roughly like this:",[207,236,240],{"className":237,"code":238,"language":239,"meta":216,"style":216},"language-apex shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","List\u003CAccount> updates = new List\u003CAccount>();\nfor (Integer i = 0; i \u003C records.size(); i++) {\n updates.add(new Account(Id = records[i].Id, Name = records[i].Name));\n}\nDatabase.update(updates, false);\n","apex",[214,241,242,250,256,262,268],{"__ignoreMap":216},[243,244,247],"span",{"class":245,"line":246},"line",1,[243,248,249],{},"List\u003CAccount> updates = new List\u003CAccount>();\n",[243,251,253],{"class":245,"line":252},2,[243,254,255],{},"for (Integer i = 0; i \u003C records.size(); i++) {\n",[243,257,259],{"class":245,"line":258},3,[243,260,261],{}," updates.add(new Account(Id = records[i].Id, Name = records[i].Name));\n",[243,263,265],{"class":245,"line":264},4,[243,266,267],{},"}\n",[243,269,271],{"class":245,"line":270},5,[243,272,273],{},"Database.update(updates, false);\n",[170,275,276,277,280,281,284],{},"The loop builds a collection. The single ",[214,278,279],{},"Database.update"," sends all of it in one context, with ",[214,282,283],{},"false"," telling the runtime to allow partial success rather than rolling the whole transaction back. That second argument is the difference between one bad row failing and your entire batch failing, and it is the line most people copy without reading.",[188,286,288],{"id":287},"running-a-bulk-job-from-start-to-finish","Running a Bulk Job From Start to Finish",[170,290,291],{},"The sequence is fixed, and the order is not negotiable.",[293,294,295,299,302,305,308],"ol",{},[296,297,298],"li",{},"Assemble every record in memory first, then validate the whole set for required fields and type mismatches before you open a connection.",[296,300,301],{},"Create the job against your target object and operation, and store the returned job identifier somewhere durable.",[296,303,304],{},"Upload the record payload to that job, in chunks if your file is large, and close the upload when the last chunk lands.",[296,306,307],{},"Poll the job status at an interval your platform tolerates, and stop polling the moment the state is terminal.",[296,309,310],{},"Retrieve the success and failure results separately, then route the failures into a retry queue with the original record attached.",[170,312,313],{},"Step five is the one teams skip and later regret. A job that completes is not a job that succeeded. Bulk endpoints report per-record outcomes precisely because partial failure is normal at volume, and a wrapper that reads only the job state will mark your integration green while a few hundred records sit unprocessed.",[188,315,317],{"id":316},"where-bulk-runs-fall-over","Where Bulk Runs Fall Over",[170,319,320],{},"The failures are consistent enough to name.",[170,322,323,326],{},[173,324,325],{},"Request size gets treated as infinite."," Every bulk endpoint has a payload ceiling, and hitting it returns a truncated upload rather than a clear error. The symptom looks like missing records with a successful job status, which sends people hunting through their application code for a bug that lives in the transport layer. Split uploads at a size you know is under the ceiling, and log the chunk boundaries.",[170,328,329,332],{},[173,330,331],{},"Concurrency goes unbounded."," When a job takes longer than expected, the instinct is to fire the next one in parallel. Now two jobs write to the same records, last-write-wins, and your reconciliation job has to guess which value is correct. Cap the number of simultaneous jobs per object in your wrapper code, not in a runbook.",[170,334,335,338],{},[173,336,337],{},"Partial success reads as total success."," This is the one that costs the most time to find, because everything looks fine. Your dashboard shows green, your logs show a 200, and the customer-facing record is stale. Always parse the failure results file and alert on a non-zero failure count.",[170,340,341],{},"There is a fourth, quieter one. Teams build the bulk path and leave the single-record path untouched, so the two code paths slowly disagree about validation rules. Then a record passes in one route and fails in the other, and nobody can explain why. Share the validation function between both paths.",[188,343,345],{"id":344},"the-moment-volume-stops-being-an-engineering-problem","The Moment Volume Stops Being an Engineering Problem",[170,347,348],{},"You have a real choice to make when send volume crosses the point where a human can no longer eyeball the queue.",[170,350,351],{},"If your volume is a nightly sync of internal records and you control both ends, a hand-rolled bulk wrapper is the right call. You know the schema, nobody is waiting on a reply, and you can absorb a failed run and retry it in the morning. Building it yourself costs you engineering hours and buys you total control.",[170,353,354,355,360],{},"Bulk messaging to customers is a different shape of problem entirely. Now the records are conversations, the failure mode is a customer who never got their order update, and the platform's rules constrain what you may send in the first place. The onboarding guidance for the WhatsApp Business Platform requires a dedicated phone number that can receive voice calls or SMS for verification (",[196,356,359],{"href":357,"rel":358},"https:\u002F\u002Fwhatsappbusiness.com\u002Fwp-content\u002Fuploads\u002F2026\u002F04\u002FOnboarding-to-the-WhatsApp-Business-Platform.pdf",[200],"WhatsApp Business Platform onboarding documentation","). That is one rule among many, and each one is a place your wrapper can be correct in isolation and wrong in combination.",[170,362,363,364,368],{},"The signals that settle it for you: your records carry a delivery expectation, your audience opted in and expects a reply, or your team needs to see the same thread the customer sees. Meet any one of those and you are no longer maintaining a data pipeline, you are running a support channel that happens to be automated. The ",[196,365,367],{"href":366},"\u002Fblog\u002Fusing-bulk-whatsapp-message-api-for-sales-a-technical-implementation-guide","technical implementation"," walkthrough for bulk sending covers what that transition asks of your code. If none of the signals apply and you are moving warehouse rows, keep your wrapper.",[188,370,372],{"id":371},"how-we-take-the-wrapper-off-your-plate","How We Take the Wrapper Off Your Plate",[170,374,375],{},"We built WhatsBox for the second case. It is a WhatsApp Business API messaging platform, and it handles the parts of a bulk run that are not about your payload. When a broadcast triggers a reply, the same agent who sees the inbox can take it over, because human-in-the-loop escalation is part of the flow rather than a separate tool bolted on.",[170,377,378,379,381,382,386],{},"You can also connect a custom-trained AI chatbot with a knowledge base for the questions that repeat, wire ",[196,380,117],{"href":118}," and Google Forms into your intake, and put a whitelabel ",[196,383,385],{"href":384},"\u002Fwhatsapp-chat-widget","chat widget"," on your site so the conversation starts where the customer already is.",[170,388,389,390,394,395,399],{},"If your bulk sends land in front of customers and someone has to answer when they reply, that is us. A bulk sending implementation guide is the place to start on the code side, and you can ",[196,391,393],{"href":392},"\u002Fcontact-us","get in touch"," to see the current ",[196,396,398],{"href":397},"\u002Fpricing","pricing",".",[188,401,403],{"id":402},"frequently-asked-questions","Frequently Asked Questions",[405,406,408],"h3",{"id":407},"what-does-bulk-api-mean","What does bulk API mean?",[170,410,411],{},"It means a single API operation that carries many records or messages, rather than one call per item. The endpoint accepts the collection, returns a job or batch identifier, and processes the records as a unit. That design exists because per-record calls spend most of their time on connection setup and round-trip latency, not on the work itself. Bulk API is the umbrella term; how a specific platform implements it differs by product.",[405,413,415],{"id":414},"how-to-call-multiple-apis-at-once","How to call multiple APIs at once?",[170,417,418],{},"Send the calls concurrently from your client and manage them as a set rather than a sequence. Each request still returns independently, so your code has to collect results by identifier and reconcile them afterward. The constraint is on the receiving side: most platforms cap simultaneous requests per account, and exceeding that cap produces throttled responses that look like failures but are not. Bound your concurrency deliberately instead of firing everything.",[405,420,422],{"id":421},"what-are-the-four-types-of-api-calls","What are the four types of API calls?",[170,424,425],{},"The four methods map to intent: GET retrieves data, POST creates a record or submits a payload, PUT replaces an existing resource, and DELETE removes one. Bulk work leans on POST, since that is the method that carries a body large enough to hold a collection. PUT shows up when you are updating records that already exist. A well-built bulk wrapper usually uses one method per job and keeps the others out of the path.",[405,427,429],{"id":428},"what-is-the-difference-between-a-bulk-api-and-a-batch-api","What is the difference between a bulk API and a batch API?",[170,431,432],{},"A batch API splits records into groups with a hard ceiling and processes each group separately, so results arrive per group. A bulk API keeps one job open and lets you stream records into it until the payload is finished, which suits sets too large for a single bounded group. The practical difference shows in retries: a failed batch is retried as a batch, while a partially failed bulk job needs per-record reconciliation because the job itself succeeded.",[434,435],"hr",{},[170,437,438,441],{},[173,439,440],{},"The wrapper is the product."," Whatever endpoint sits underneath, the code you write around job creation, polling, failure routing, and retry decides whether your bulk calls hold up at volume. Get that right and the API choice becomes a much smaller decision than it first appears.",[443,444,445],"style",{},"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);}",{"title":216,"searchDepth":252,"depth":252,"links":447},[448,449,450,451,452,453],{"id":190,"depth":252,"text":191},{"id":287,"depth":252,"text":288},{"id":316,"depth":252,"text":317},{"id":344,"depth":252,"text":345},{"id":371,"depth":252,"text":372},{"id":402,"depth":252,"text":403,"children":454},[455,456,457,458],{"id":407,"depth":258,"text":408},{"id":414,"depth":258,"text":415},{"id":421,"depth":258,"text":422},{"id":428,"depth":258,"text":429},"2026-10-02","Bulk API calls bundle many records into a single request so you stop paying connection overhead per record.",false,"md",{"src":183},{},true,"\u002Fblog\u002Fbulk-api-calls-what-the-docs-skip-before-you-push-volume",null,{"title":158,"description":460},{"loc":466},"blog\u002Fbulk-api-calls-what-the-docs-skip-before-you-push-volume","4cqbRsgHbDptYUhMlYMpwgebRbqe1oiFn0Ajg9zAicw",[467,473],{"title":474,"path":475,"stem":476,"description":477,"children":-1},"WhatsApp Business Solutions: What Actually Runs the Pipeline","\u002Fblog\u002Fwhatsapp-business-solutions-what-actually-runs-the-pipeline","blog\u002Fwhatsapp-business-solutions-what-actually-runs-the-pipeline","WhatsApp business solutions built on the official Business API are a message pipeline, not a chat app. Here is how the pipeline works, where it leaks, and what to configure before volume arrives."]