Connect Bubble to Monday.com by configuring Bubble's API Connector as a GraphQL client — POST all queries to the single endpoint https://api.monday.com/v2 with a Bearer token in a Private header. Monday.com has no REST API; every read and write is a GraphQL query or mutation sent in the request body. Keep Authorization Private so the token never reaches the browser.
| Fact | Value |
|---|---|
| Tool | Monday.com |
| Category | Productivity |
| Method | Bubble API Connector |
| Difficulty | Intermediate |
| Time required | 2–3 hours |
| Last updated | July 2026 |
Monday.com is GraphQL-Only — Here Is How Bubble Handles That
Most APIs Bubble builders encounter are REST APIs with different URLs for different resources — GET /tasks, POST /users, PATCH /items/123. Monday.com is different: there is exactly one URL (https://api.monday.com/v2) and every operation is a POST request where the 'query' field in the body determines what you are doing. This is GraphQL, and it requires a small mental shift when using Bubble's API Connector.
The good news: Bubble's API Connector does not care whether you are calling a REST endpoint or a GraphQL endpoint — it sends whatever you configure. You configure the call as a POST with a JSON body and put your GraphQL query string inside a 'query' key. For mutations (creating or updating items), you add a 'variables' object alongside the query. Bubble then treats the JSON response like any other API response and lets you map fields to your Data types.
The Authorization token (generated in your Monday.com Developer Center) goes in a shared header marked Private. This means Bubble's servers send the header on your behalf — it never appears in browser network traffic, so your entire workspace is not exposed if someone inspects the page.
The main Monday.com-specific friction point is column_values. When you fetch board items, each item's columns come back as an array of objects. If you request all columns for a large board, Monday's API responds with a 'ComplexityBudgetExhausted' error because the cost calculation is based on the number of fields returned. The fix is always to specify exactly which column IDs you need: column_values(ids: ["status", "person"]) instead of column_values. This keeps complexity low and responses fast.
For write operations — creating items, updating status, assigning people — Monday uses GraphQL mutations. The syntax for column value updates requires a JSON string embedded inside the GraphQL argument, which is a common source of 400 errors for beginners. This guide shows the exact format.
Integration method
Monday.com GraphQL API called from Bubble's API Connector with the Bearer token in a Private header — all requests run server-side, keeping the token out of the browser.
Prerequisites
- A Monday.com account on any paid plan (Basic, Standard, Pro, or Enterprise) — API access is available on all paid plans
- Your Monday.com API v2 personal access token — generate it in Monday.com under your avatar → Developers → My Access Tokens → Generate Token
- The numeric board ID(s) you want to work with — visible in the board URL (monday.com/boards/1234567890)
- A Bubble app with the API Connector plugin installed — go to Plugins tab → Add plugins → search 'API Connector' → Install
- Basic familiarity with Bubble workflows and Repeating Groups
Step-by-step guide
Generate Your Monday.com API Token and Locate Board IDs
Before touching Bubble, you need two pieces of information from Monday.com: your API token and the numeric ID of the board you want to connect. To generate your API token: log in to Monday.com → click your avatar or profile photo in the bottom-left corner → select 'Developers' → under 'My Access Tokens', click 'Show' next to the v2 token → copy the full token string. This token gives the same access permissions as your Monday.com account, so keep it secure. To find your board ID: open the board in Monday.com and look at the URL in your browser. It will look like monday.com/boards/1234567890. The number at the end is your board ID. Write it down — you will use it directly in the GraphQL query body in a later step. If you have multiple boards for different clients or projects, note each board ID. You can build a Bubble dropdown that lets users select which board to view, with the board IDs stored in a Bubble Data type. For now, start with one board to confirm the connection.
Pro tip: Monday.com API tokens do not expire automatically, but if you revoke and regenerate one you must update the Private header in Bubble's API Connector. Treat this token like a password — never paste it into Bubble's non-Private fields.
Expected result: You have a Monday.com API v2 token string and at least one numeric board ID ready to use in the next step.
Add the API Connector and Configure Monday.com Shared Headers
Now set up the Monday.com connection in Bubble's API Connector. This is where you configure the two shared headers that all Monday.com calls will use. In your Bubble editor, click 'Plugins' in the left sidebar → click 'Add plugins' → search for 'API Connector' → click Install on the plugin by Bubble. Once installed, click 'API Connector' in the plugins list to open its configuration panel. Click 'Add another API' to create a new API group. Name it 'Monday.com'. Under 'Authentication', choose 'Private key in header' if the option appears, or leave as 'None' and add headers manually. In the 'Shared headers' section, add two headers: Header 1: Key = Authorization, Value = Bearer YOUR_TOKEN_HERE (replace YOUR_TOKEN_HERE with the token from Step 1). Check the 'Private' checkbox next to this header — this is critical. The Private flag means Bubble sends this header from its servers and it never appears in browser requests. Header 2: Key = Content-Type, Value = application/json. This header does NOT need to be Private — it is not sensitive. Leave the base URL field empty — with GraphQL you will use the full URL in each individual call since there is only one endpoint anyway.
1{2 "shared_headers": [3 {4 "key": "Authorization",5 "value": "Bearer YOUR_MONDAY_API_TOKEN",6 "private": true7 },8 {9 "key": "Content-Type",10 "value": "application/json",11 "private": false12 }13 ]14}Pro tip: Double-check that the Private checkbox is checked for the Authorization header. If it is unchecked, the full token will be visible in your users' browser DevTools network tab — anyone using your app could extract it and access your entire Monday.com workspace.
Expected result: A Monday.com API group exists in your API Connector with the Authorization Bearer token (Private) and Content-Type headers configured. No calls have been added yet.
Add and Initialize a Boards List Call
Create your first API call — a query that lists your boards. This verifies that the token works and gives you a call you can reuse for board selection dropdowns. In the Monday.com API group, click 'Add a call'. Name it 'Get Boards'. Set the method to POST and the URL to https://api.monday.com/v2. In the Body section, check 'Send arbitrary data' — this allows you to send raw JSON. In the body text area, paste: {"query": "{ boards(limit: 20) { id name description } }"} This GraphQL query fetches the first 20 boards with their IDs, names, and descriptions. Set 'Use as' to 'Data' — this tells Bubble the call returns data you want to display, not just trigger an action. Click 'Initialize call'. Bubble will send the request to Monday.com and receive a real response. If initialization succeeds, you will see detected fields like data > boards > id, name, description. If you see an error: - 401 Unauthorized: check that the Authorization header value is 'Bearer TOKEN' (with the space) and that Private is checked. - 200 with empty boards array: you have a valid token but no boards are visible to this token — confirm the token belongs to an account with boards. After successful initialization, Bubble maps the response automatically. Click 'Save'.
1{"query": "{ boards(limit: 20) { id name description } }"}Pro tip: If initialization fails with 'There was an issue setting up your call', Monday.com returned an unexpected response shape. This usually means the body was not parsed as JSON — confirm that 'Send arbitrary data' is checked and Content-Type is set to application/json in shared headers.
Expected result: The 'Get Boards' call initializes successfully and Bubble detects fields data > boards with id and name. You can see your Monday.com board names in the preview response.
Add a Board Items Call with Column Value Filtering
Now add the call that fetches items from a specific board, including selected column values. This is the call your Repeating Group will use to display board data. Add another call in the Monday.com group. Name it 'Get Board Items'. Method: POST. URL: https://api.monday.com/v2. Check 'Send arbitrary data'. In the body, use the following query — replace 1234567890 with your actual board ID, and replace 'status' and 'person' with the actual column IDs from your board: {"query": "{ boards(ids: [1234567890]) { items_page { items { id name column_values(ids: [\"status\", \"person\"]) { column { title } text } } } } }"} The column IDs (like 'status', 'person', 'date4') are not the display names — they are internal identifiers. To find them: in Monday.com, open the board → click the three-dot menu on a column → 'Column settings' → the ID appears at the bottom, or check the URL when you hover the column header. Always use column_values(ids: [...]) with explicit IDs rather than column_values without filtering. Requesting all columns on a large board returns a 'ComplexityBudgetExhausted' error because Monday.com charges complexity units per field returned. Set 'Use as' to 'Data'. Click 'Initialize call'. Bubble detects the nested structure: data > boards > items_page > items > each item with id, name, and column_values. Map the column_values text field to the display you need in your Repeating Group.
1{2 "query": "{ boards(ids: [1234567890]) { items_page { items { id name column_values(ids: [\"status\", \"person\"]) { column { title } text } } } } }"3}Pro tip: To make the board ID dynamic (so users can switch boards), add a query parameter or use a separate initialization with a board ID variable. Monday.com GraphQL also supports variables: {"query": "query($boardId: ID!) { boards(ids: [$boardId]) { ... } }", "variables": {"boardId": "1234567890"}} — Bubble can set the variable value dynamically from a workflow step.
Expected result: The 'Get Board Items' call initializes and Bubble detects the items array with name and column_values fields. You can bind this call to a Repeating Group to display board items.
Add a Create Item Mutation for Form Submissions
To let users create Monday.com items from a Bubble form, you need a GraphQL mutation call. This is how you write data back to Monday.com. Add a new call in the Monday.com group. Name it 'Create Item'. Method: POST. URL: https://api.monday.com/v2. Check 'Send arbitrary data'. The mutation body looks like this: {"query": "mutation { create_item (board_id: <BOARD_ID>, item_name: \"<ITEM_NAME>\") { id name } }"} However, you want the item name to be dynamic (coming from a Bubble input). Switch the 'Use as' setting to 'Action' — this means the call is triggered by a workflow step, not data display, and it can accept dynamic values from Bubble's workflow expression editor. Make the item name a dynamic parameter: in the body, replace the hardcoded item name with <dynamic value - ITEM_NAME> using Bubble's parameter syntax. Bubble will prompt you to set this value when you use the call in a workflow. For adding column values (such as setting a status or assigning a person when creating the item), the body includes a column_values argument as a JSON string: {"query": "mutation { create_item (board_id: 1234567890, item_name: \"<ITEM_NAME>\", column_values: \"{\\\"status\\\": {\\\"label\\\": \\\"New Request\\\"}}\") { id name } }"} The nested escaping looks intimidating but follows a consistent pattern: the column_values argument is a JSON string, so the inner JSON must be escaped with backslashes within the GraphQL argument string. Click 'Initialize call' with a test item name — initialization creates a real item in Monday.com. Check your board after initializing to confirm the item appears, then delete the test item manually.
1{2 "query": "mutation { create_item (board_id: 1234567890, item_name: \"Test Item from Bubble\", column_values: \"{\\\"status\\\": {\\\"label\\\": \\\"New Request\\\"}}\") { id name } }"3}Pro tip: If you see a 400 error when creating items with column_values, the most common cause is incorrect JSON escaping inside the GraphQL string. Test your column_values format using Monday.com's API Playground (accessible from Developer Center) before adding it to Bubble — the playground shows exact error messages.
Expected result: The 'Create Item' action call initializes successfully, a test item appears on your Monday.com board, and you can trigger this call from a Bubble button workflow with a dynamic item name value.
Build the Repeating Group and Workflow
With your API calls initialized, wire everything together in the Bubble editor to create a working board view and form submission flow. For the board view Repeating Group: drag a Repeating Group element onto your page. In its data source, select 'Get data from an external API' → choose 'Monday.com - Get Board Items'. Set 'Data source' to the items array returned by the call. In the Repeating Group's cell, add Text elements and bind them to 'Current cell's Monday.com - Get Board Items's name' and the column_values text field for status and person. For form submission: add Input elements for the item name and any other fields. Add a Button. In the Button's Workflow, add the action 'Plugins → Monday.com - Create Item'. Set the ITEM_NAME parameter to the value of your name Input element. You can chain additional steps — for example, after creating the item, run 'Refresh data source' on the Repeating Group so the new item appears immediately. For privacy: if your Bubble app stores any Monday.com item data in a Bubble database table, go to Data tab → Privacy → set rules on that data type so only authorized users can read the stored items. Bubble's Privacy rules are the main guardrail against users accessing each other's data. For WU economy: Monday.com data that does not change frequently (board names, team structures) can be cached in a Bubble database table, refreshed on a schedule via a Backend Workflow (paid plan), rather than fetched live on every page load. This reduces both WU consumption and API complexity usage. RapidDev's team has built hundreds of Bubble apps with integrations like this — if you need help designing the full Monday.com portal architecture, book a free scoping call at rapidevelopers.com/contact.
Pro tip: Add a loading state to your Repeating Group by showing a 'Loading...' text element that is only visible when the Repeating Group's data source is loading. This prevents users from thinking the app is broken when waiting for the Monday.com API response.
Expected result: Your Bubble page shows a Repeating Group displaying Monday.com board items. A form with a button creates new items in Monday.com when submitted. Both flows work end-to-end in the Bubble preview.
Common use cases
Client-Facing Project Status Portal
A Bubble app where clients log in and see the live status of their project items on a Monday.com board. Each client is associated with a board ID stored in Bubble's database. The app fetches only the Status and Timeline columns using column_values(ids) to stay within complexity limits, then displays the data in a styled Repeating Group.
Write a Monday.com GraphQL query that fetches items from board 1234567 and returns only the status and person column values, plus each item's name and ID, formatted as a JSON body for Bubble's API Connector POST call.
Copy this prompt to try it in Bubble
Intake Form That Creates Monday Items
A Bubble form collects project requests from visitors. On submission, a workflow fires a Monday.com create_item mutation, creating a new item in the intake board with the form data mapped to columns. The Bubble user sees a confirmation with the returned item ID.
Write a Monday.com GraphQL create_item mutation that creates an item in list 9876543 with item_name from a Bubble input, status column set to 'New Request', and a text column containing the description input — formatted as the API Connector POST body.
Copy this prompt to try it in Bubble
Operations Dashboard Pulling Multiple Boards
An internal Bubble dashboard that lets ops team members switch between Monday.com boards using a Dropdown element. Selecting a board fires an API Connector call that fetches the board's items and populates a Repeating Group. A second workflow action lets the user update item status directly from Bubble.
Write a Monday.com GraphQL query that accepts a board ID as a variable and returns all items with their names and status column values — show the full query and variables object formatted for Bubble's API Connector.
Copy this prompt to try it in Bubble
Troubleshooting
API Connector returns 401 Unauthorized on every Monday.com call
Cause: The Authorization header value is malformed or the Private checkbox is not checked, causing the header to be sent incorrectly or not at all.
Solution: Open the Monday.com group in the API Connector → check Shared Headers → verify the Authorization value starts with 'Bearer ' (with a space) followed by the token. Confirm the Private checkbox is checked. If you copied the token with extra whitespace, regenerate it in Monday.com Developer Center and paste it fresh.
GraphQL query returns 'ComplexityBudgetExhausted' error
Cause: The query is fetching all column_values without filtering by column ID. Monday.com calculates complexity per field returned, and large boards with many columns quickly exceed the 1,000,000 units per minute budget.
Solution: Add the ids filter to column_values in your query: column_values(ids: ["status", "person"]) instead of column_values. Also reduce the items per page using items_page(limit: 25) and implement pagination rather than fetching all items at once.
1{ boards(ids: [1234567890]) { items_page(limit: 25) { items { id name column_values(ids: ["status", "person"]) { column { title } text } } } } }'There was an issue setting up your call' when initializing in API Connector
Cause: The Initialize call requires a real successful response from Monday.com. If the board ID does not exist, the query has a syntax error, or the token lacks permission, Monday returns an error body that Bubble cannot map as a schema.
Solution: Before initializing in Bubble, test the exact query in Monday.com's API Playground (Developer Center → API Playground). Confirm the query returns data with the expected shape. Fix any syntax errors there first, then paste the working query into Bubble and re-initialize.
create_item mutation returns 400 with 'ColumnValueException' or 'ArgumentLiteralParseError'
Cause: The column_values argument contains incorrectly escaped JSON. Monday.com expects a JSON string (not a JSON object) for column_values, meaning the inner JSON must be escaped with backslashes when embedded in the GraphQL string.
Solution: Verify your column_values format using Monday.com's column types documentation. For a status column: "{\"label\": \"Done\"}" — the outer quotes are the GraphQL string delimiter, the inner keys and values must be escaped. Use Monday.com's API Playground to confirm the mutation works before adding it to Bubble.
1{"query": "mutation { create_item (board_id: 1234567890, item_name: \"My Item\", column_values: \"{\\\"status\\\": {\\\"label\\\": \\\"New\\\"}}\") { id } }"}Best practices
- Always mark the Authorization Bearer token as Private in the API Connector shared headers — Monday.com tokens give full workspace access and must never appear in browser network traffic.
- Always filter column_values with specific column IDs (column_values(ids: ["status"])) — fetching all columns is the fastest way to hit Monday.com's complexity budget and cause 'ComplexityBudgetExhausted' errors on large boards.
- Use GraphQL variables ({"query": "...", "variables": {"boardId": ...}}) instead of hardcoding IDs in query strings when board IDs need to be dynamic — this keeps queries readable and makes Bubble's dynamic parameter substitution cleaner.
- Cache static Monday.com data (board names, workspace structure) in a Bubble database table updated by a scheduled Backend Workflow — this reduces WU consumption and avoids live API calls on every page load.
- Set up Privacy rules in Bubble's Data tab for any Monday.com data you store in the database — this prevents users from querying each other's project data through the Data API.
- Test mutations in Monday.com's official API Playground before adding them to Bubble — the Playground shows exact error messages and lets you iterate on GraphQL syntax without burning through Bubble Initialize calls.
- Use items_page with a limit parameter and implement pagination in your Repeating Group rather than fetching all items — this keeps individual API response sizes small and UI rendering fast.
- For write-back mutations from public-facing app pages, use a Backend Workflow (API Workflow) as the trigger rather than a client-side workflow action — this keeps the mutation on Bubble's servers and requires a paid Bubble plan.
Alternatives
ClickUp uses a REST API with separate endpoints per resource and a simple Bearer token header — much easier to set up in Bubble's API Connector than Monday.com's GraphQL. Choose ClickUp if your team already uses it or if the GraphQL syntax feels too complex for your use case.
Asana provides a REST API with straightforward GET/POST endpoints for tasks and projects, making it simpler to configure in Bubble than Monday.com's single GraphQL endpoint. Asana is a better fit if you need a simpler task hierarchy without Monday.com's board-and-column model.
Notion's REST API works well as a Bubble backend CMS — teams edit content in Notion and the Bubble app displays it. If your primary need is content management (articles, wikis, team documentation) rather than task tracking, Notion is often easier to integrate than Monday.com.
Frequently asked questions
Does Monday.com have a REST API I can use instead of GraphQL in Bubble?
No — Monday.com's API is GraphQL-only. There is no REST alternative. However, Bubble's API Connector handles GraphQL perfectly when configured as a POST call with a JSON body containing the 'query' key. You do not need a dedicated GraphQL client.
Can I use Monday.com on the free Bubble plan?
Yes, for read-only data display. API Connector calls (fetching and showing Monday.com board items) work on Bubble's free plan. Creating items from a public-facing app without exposing your token requires a Backend Workflow, which is a paid Bubble plan feature.
How do I find my column IDs to use in column_values(ids: [...])?
In Monday.com, open your board → click the three-dot menu (⋮) on a column header → 'Column settings' → the column ID appears at the bottom of the settings panel. Common IDs are 'status', 'person', 'date4', 'text0' — but they vary by board. You can also run a query without IDs filtering first, look at the raw response in Bubble's Initialize popup, and note the column IDs there.
What Monday.com plan do I need for API access?
API access is available on all paid Monday.com plans — Basic ($9/seat/mo), Standard, Pro, and Enterprise. The free Monday.com plan does not include API access. There is no free tier for API usage.
Can my app users connect their own Monday.com accounts instead of using my token?
Yes, but that requires OAuth 2.0 instead of a personal access token. OAuth lets each user authorize your app with their own Monday.com account. This is significantly more complex to implement in Bubble and typically requires a Backend Workflow (paid plan) to handle the token exchange. For internal tools, a single shared personal token is simpler.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation