{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Webhooks"},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"webhooks","__idx":0},"children":["Webhooks"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["MoreLogin can POST a JSON event to an HTTPS endpoint you own as soon as a cloud phone or cloud browser operation reaches its final result, so you no longer have to poll for the outcome. One callback URL is stored per team, and the Local API and Open API write to the same record."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"configure-the-callback-url","__idx":1},"children":["Configure the callback URL"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Both surfaces expose the same operation. Open API:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl -X POST \"https://api.morelogin.com/webhook/config\" \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -d '{\n    \"callbackUrl\": \"https://example.com/morelogin/webhook\",\n    \"enabled\": true\n  }'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Local API:"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl -X POST \"http://127.0.0.1:40000/api/webhook/config\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"callbackUrl\": \"https://example.com/morelogin/webhook\",\n    \"enabled\": true\n  }'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The Local API route is served by the desktop client, so it needs MoreLogin client v2.66.0 or higher. The Open API endpoint has no client dependency."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["teamId"]}," is never read from the request. Each call configures the team of the server-side context, so you cannot point another team's events at your endpoint."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The URL must be HTTPS, 1 to 1024 characters, with a host, no user info, no fragment and a valid port. Every address it resolves to has to be publicly routable: localhost, private, link-local, CGNAT, cloud metadata, protocol-reserved, documentation and 6to4 ranges are rejected with ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/api-reference/getting-started/error-codes"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["41001"]}]},". The same check runs again when a delivery opens its connection, so a hostname that later resolves into a private range fails that delivery rather than reaching your network."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Saving is an upsert keyed by team, so sending the same body twice is harmless."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"turning-delivery-off","__idx":2},"children":["Turning delivery off"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["enabled: false"]}," keeps the URL on file and stops new events from being created. Events already queued are cancelled one at a time, at the moment each would next be authorized, and only while the configuration is still disabled — so if you re-enable quickly, queued events continue instead of being dropped."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-a-delivery-looks-like","__idx":3},"children":["What a delivery looks like"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each delivery is a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST"]}," with these headers:"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Header"},"children":["Header"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Content-Type"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["application/json"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["User-Agent"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MoreLogin-Webhook/1.0"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Event-Id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Same as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]}," in the body"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-Event-Type"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Same as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventType"]}," in the body"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The two ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["X-Webhook-*"]}," headers duplicate body fields on purpose, so a router or queue can dispatch on them without parsing JSON."]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"eventId\": \"c7f3a2b10d8e4f6a9c1b2d3e4f5a6b7c\",\n  \"eventType\": \"cloud_phone.power_off\",\n  \"eventTime\": \"1787241600000\",\n  \"data\": {\n    \"teamId\": \"10001\",\n    \"cloudPhoneId\": \"20001\",\n    \"reason\": \"MONEY_SAVING\"\n  },\n  \"result\": {\n    \"success\": true,\n    \"code\": \"0\",\n    \"message\": null\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Unique event ID. Retries and internal replays of the same event reuse it, so it is the idempotency key"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventType"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Stable event name, from the table below"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventTime"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When the final result happened, as Unix epoch milliseconds. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sent as a string"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.teamId"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Team that owns the resource. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sent as a string"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.cloudPhoneId"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Cloud phone the event is about. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sent as a string"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.cloudBrowserId"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Cloud browser profile the event is about. ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Sent as a string"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.runId"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Cloud browser run instance the event is about"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.reason"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Only on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.power_off"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_browser.stop"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.success"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Whether the operation ultimately succeeded"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.code"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["0"]}," on success; otherwise a stable business error code that does not depend on language"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.message"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["null"]}," on success; otherwise an explanation in the team's language, falling back to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["en-US"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Every numeric identifier and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventTime"]}," arrive as JSON strings, matching the rest of the API — see ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/api-reference/getting-started/response-format"},"children":["Common Response Format"]},". Parse them as strings, not as numbers, or you will lose precision on 64-bit IDs."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"events","__idx":4},"children":["Events"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"eventType"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventType"]}]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Final result it reports"},"children":["Final result it reports"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.power_on"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Power on succeeded or failed"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.power_off"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Power off succeeded. A failed shutdown produces no event"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.restart"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Restart succeeded or failed"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.reset"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Reset succeeded or failed"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.new_machine"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["One-click new machine succeeded or failed"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_browser.start"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Cloud browser start succeeded or failed"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_browser.stop"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Each cloud browser stop attempt, successful or not"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Cloud phone events carry ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["teamId"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloudPhoneId"]},". Cloud browser events carry ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["teamId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloudBrowserId"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["runId"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Power on, restart, reset and one-click new machine report ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["success: true"]}," only once the provider callback succeeded and the local synchronisation committed. A billing failure, or an asynchronous proxy check that fails and finishes its cleanup, reports a failed power on and does ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["not"]}," additionally emit a power off. Deferred work such as installing preset apps or clearing expired files does not change the result."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If a shutdown interrupts a boot, that attempt produces no power-on event; the later successful shutdown still produces its own ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.power_off"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"stop-reasons","__idx":5},"children":["Stop reasons"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_phone.power_off"]}," adds ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.reason"]},":"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Meaning"},"children":["Meaning"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NORMAL"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ordinary shutdown"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MONEY_SAVING"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Money-saving mode"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OTHER"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Arrears, expiry, maintenance or anything else"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["cloud_browser.stop"]}," adds ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["data.reason"]},":"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Value"},"children":["Value"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Meaning"},"children":["Meaning"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["NORMAL"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ordinary close"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["MONEY_SAVING"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Money-saving mode"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ENERGY_SAVING"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Energy-saving mode"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["BROWSER_EXITED"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["The browser exited unexpectedly"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["OTHER"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Anything else"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["An internal archiving failure changes only ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result"]},"; it never overwrites the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["reason"]}," captured when the stop began."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"delivery-retries-and-ordering","__idx":6},"children":["Delivery, retries and ordering"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Any ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," counts as delivered. Every other status, plus connect and read timeouts and network errors, counts as a failure. The connect timeout is 5 seconds and the read timeout is 30 seconds."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A failed delivery is retried at most 6 times, after 10 seconds, 30 seconds, 60 seconds, 3 minutes, 10 minutes and 30 minutes. That is at most 7 requests for one event. After the sixth retry fails the event stops being retried automatically."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Events for the same cloud phone, or the same cloud browser, are delivered in creation order, one at a time. Different resources are delivered in parallel, so do not assume any ordering between them."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Retries of one event always reuse the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventTime"]}," and body. Under network or recovery edge cases the same event may be delivered more than once with those values unchanged, so ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["deduplicate on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]}]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For cloud browser stops, one stop attempt yields exactly one event. A later manual retry, a manual forced release, or a system-initiated forced release is a new operation and gets a new ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]},". Two attempts are never merged into one event."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Cloud phone operations are identified by the provider task ID, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["traceId"]},", or a stable business timestamp. When none of those exists the service generates a UUID and treats the current final callback as a new operation, so you get a new ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]}," rather than two different operations collapsing into one."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"writing-the-receiver","__idx":7},"children":["Writing the receiver"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Return a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2xx"]}," as soon as you have stored the event, and do the real work asynchronously. The response body is ignored, and a slow handler burns your 30-second read budget and pushes the event into the retry schedule even though you received it."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Deduplicate on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["eventId"]},". Treat a repeat as already handled rather than replaying side effects."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Do not treat the payload as trusted input just because it arrived at your endpoint. This release does not sign callbacks, so anyone who learns your URL can post to it. Use a URL that is hard to guess, and before acting on anything expensive, confirm the state through the API — for example ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/api-reference/cloud-phone/open-api"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /cloudphone/info"]}]}," for a cloud phone, or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /cloudbrowser/page"]}," for a cloud browser run."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.code"]}," uses the same business codes as the synchronous API, so a failure can be looked up in ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/api-reference/getting-started/error-codes"},"children":["Error Codes"]},". ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.message"]}," is a human-readable string whose wording and language can change; branch on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.success"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.code"]},", never on ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["result.message"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The machine-readable contract for every event, including schemas and per-event examples, is published with the shared resources spec under ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"/api-reference/shared-resources/open-api"},"children":["Shared Resources Open API"]},"."]}]},"headings":[{"value":"Webhooks","id":"webhooks","depth":1},{"value":"Configure the callback URL","id":"configure-the-callback-url","depth":2},{"value":"Turning delivery off","id":"turning-delivery-off","depth":3},{"value":"What a delivery looks like","id":"what-a-delivery-looks-like","depth":2},{"value":"Events","id":"events","depth":2},{"value":"Stop reasons","id":"stop-reasons","depth":3},{"value":"Delivery, retries and ordering","id":"delivery-retries-and-ordering","depth":2},{"value":"Writing the receiver","id":"writing-the-receiver","depth":2}],"frontmatter":{"seo":{"title":"Webhooks"}},"lastModified":"2026-09-03T02:52:33.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/api-reference/getting-started/webhooks","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}