Hello Miro Support Team and Community,
I am trying to set up a webhook subscription for a Miro board (boardId: [A specific Board ID]) to receive real-time updates on board events. I am using Postman to send the subscription request to the Miro API, and a Cloudflare Worker as my callbackUrl to handle the webhook challenge.
I have meticulously followed the official Miro API documentation for "Create board subscription" and "Getting started with webhooks."
Here's a summary of my setup and the issue:
1. Postman Request (to Miro API):
- URL:
https://api.miro.com/v2-experimental/webhooks/board_subscriptions(Confirmed correct based on Miro's latest documentation) - Method:
POST - Authorization: Bearer Token (Confirmed valid and provided in request headers)
- Body (raw, JSON): JSON
{
"boardId": "[Your Board ID]", // Placeholder for your specific board ID
"callbackUrl": "[Your Cloudflare Worker URL]", // Placeholder for your specific callback URL
"status": "enabled"
} - Result in Postman:
400 Bad Requestwith the message: "An error occurred while exchanging the callback challenge. Verify that the callback URL is valid."
2. Cloudflare Worker (My callbackUrl webhook listener):
- Purpose: To receive and respond to Miro's webhook challenge.
- Code: The Worker is deployed with robust code designed to handle both standard
POSTchallenges (expectingchallengein body) and unexpectedGETchallenges (expectingchallengein query parameters, or providing a fallback dummy string if nochallengeis found).
3. Observed Behavior (Miro's challenge to my Cloudflare Worker): Upon sending the Postman request, Miro attempts to validate my callbackUrl.
- Miro Documentation States: The webhook challenge should be a
POSTrequest with thechallengestring in the request body. - Actual Cloudflare Worker Logs Show (Consistently):
Incoming request received: GET [Your Cloudflare Worker URL](Miro consistently sends a GET request, not a POST)Request parameters (GET): {}(The GET request has no query parameters, so no 'challenge' is found here)Unexpected GET with no challenge param. Sending a dummy challenge string.Miro webhook challenge detected. Responding with challenge value: miro_challenge_response- The Worker sends a
200 OKresponse withContent-Type: text/plainand the bodymiro_challenge_response.
My Core Questions:
- Why is Miro sending a
GETrequest for the webhook challenge to mycallbackUrlwhen the documentation explicitly states it should be aPOSTrequest? - If the challenge is sent via
GET, where exactly is thechallengestring located? My logs confirm it is not in the URL's query parameters and, by definition of a GET, not in the request body. Is it expected to be in headers, or is there another mechanism forGETchallenges? - Given that my Cloudflare Worker is now successfully responding to the observed
GETrequest with a200 OKand a placeholder challenge string, why am I still receiving a400 Bad Requestfrom Miro? Is there a strict requirement for the response to come from aPOSTeven if the incoming challenge was aGET? Or is the placeholder challenge string not sufficient, and a specific, unknown value is required?
I've exhausted all troubleshooting steps on my end, relying on the documentation and adapting to observed behavior, but this inconsistency is preventing me from creating webhook subscriptions. Any assistance or clarification from Miro Support or anyone in the community who has faced this specific challenge would be greatly appreciated.
Thank you.


