{
  "doc": {
    "id": "cloud/integrations/webhooks",
    "title": "Integrate Webhooks with Cypress Cloud",
    "description": "Send Cypress Cloud run events to your own HTTPS endpoints, and verify their authenticity with a signing secret.",
    "section": "cloud",
    "source_path": "/llm/markdown/cloud/integrations/webhooks.md",
    "version": "b4b6c6d032cfec7c0d8b4e4f4e55bd0096d01203",
    "updated_at": "2026-08-31T21:43:49.892Z",
    "headings": [
      {
        "id": "cloud/integrations/webhooks#webhooks-integration",
        "text": "Webhooks Integration",
        "level": 1
      },
      {
        "id": "cloud/integrations/webhooks#why-cypress-cloud-webhooks",
        "text": "Why Cypress Cloud Webhooks",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#getting-started",
        "text": "Getting started",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#create-a-webhook",
        "text": "Create a webhook",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#send-a-test-event",
        "text": "Send a test event",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#manage-webhooks",
        "text": "Manage webhooks",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#events",
        "text": "Events",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#payload",
        "text": "Payload",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#request-headers",
        "text": "Request headers",
        "level": 3
      },
      {
        "id": "cloud/integrations/webhooks#run-completed-payload",
        "text": "run.completed payload",
        "level": 3
      },
      {
        "id": "cloud/integrations/webhooks#verify-webhook-signatures",
        "text": "Verify webhook signatures",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#how-the-signature-is-computed",
        "text": "How the signature is computed",
        "level": 3
      },
      {
        "id": "cloud/integrations/webhooks#verify-a-signature-in-your-handler",
        "text": "Verify a signature in your handler",
        "level": 3
      },
      {
        "id": "cloud/integrations/webhooks#delivery-history-and-retries",
        "text": "Delivery history and retries",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#retry-behavior",
        "text": "Retry behavior",
        "level": 3
      },
      {
        "id": "cloud/integrations/webhooks#security",
        "text": "Security",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#troubleshooting",
        "text": "Troubleshooting",
        "level": 2
      },
      {
        "id": "cloud/integrations/webhooks#run-completed-webhook-fires-too-late",
        "text": "Run completed webhook fires too late",
        "level": 3
      }
    ]
  },
  "content": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "depth": 1,
        "children": [
          {
            "type": "text",
            "value": "Webhooks Integration"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Webhooks let Cypress Cloud send a real-time HTTP request to an endpoint you own whenever a selected event occurs, for example when a run finishes."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Why Cypress Cloud Webhooks"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A webhook lets you build custom automations: update a dashboard, open a ticket, gate a deployment, or forward results into any internal system."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Following the increased pace of AI-driven development, custom workflows have become more important than ever. You may use the initial \"run completed\" webhook in multiple ways:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Triage runs programmatically for certain characteristics that require attention, then dive deeper using tools like Cypress Cloud "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/cloud/integrations/cloud-cli.md",
                    "children": [
                      {
                        "type": "text",
                        "value": "CLI"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " or "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/cloud/integrations/cloud-mcp.md",
                    "children": [
                      {
                        "type": "text",
                        "value": "MCP"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " to retrieve specific failures or other details."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Automatically feed results into your own custom real-time reporting."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Create Jira issues based on failed runs."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Deliver customized Slack notifications, or notifications in any platform, based on criteria that are not customizable in Cypress Cloud."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "While Cypress Cloud already has many built-in methods of notifications related to run statuses (for example, "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/app/core-concepts/open-mode.md#Cloud-run-notifications",
            "children": [
              {
                "type": "text",
                "value": "Desktop notifications"
              }
            ]
          },
          {
            "type": "text",
            "value": " and "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/integrations/slack.md",
            "children": [
              {
                "type": "text",
                "value": "Slack"
              }
            ]
          },
          {
            "type": "text",
            "value": " messages), webhooks deliver a raw JSON payload to your own service."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Early access: Webhooks will be available on all paid plans and during trials. The feature is rolling to admins and owners of Cypress Cloud organizations gradually, and may not yet be available for every organization. If you do not see webhooks in your project settings but want to try it early, contact your Cypress representative."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Getting started"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "You need two things to get started:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "The ability to manage webhooks for the project. You must be an Owner, Admin, or Team Admin of your Cypress Cloud organization organization. See "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/cloud/account-management/users.md#User-roles",
                    "children": [
                      {
                        "type": "text",
                        "value": "User roles"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " for details. Anyone who can view the project can view webhooks, but only those roles can create, edit, enable, disable, delete, test, or redeliver them."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "A publicly-reachable endpoint that accepts `POST` requests. HTTPS is recommended. Cypress Cloud will not deliver to private, loopback, or internal network addresses (see "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Security",
                    "children": [
                      {
                        "type": "text",
                        "value": "Security"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": "). HTTP URLs are accepted, but be aware HTTP payloads travel unencrypted."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Webhooks are configured per project. You can create up to 5 webhooks per project."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Create a webhook"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": true,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Open your project and click Settings at the bottom of the project sidebar."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Open the General tab and locate the Webhooks panel."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Click Add webhook."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In the Add webhook dialog, configure the following:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Payload URL (required): The URL Cypress Cloud will send a `POST` request to, for example `https://example.com/receive-webhook`."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Secret (optional, recommended): A signing secret used to verify that a request genuinely came from Cypress Cloud. Provide your own value (at least 16 characters) or click Generate secret to create a random one. Copy and store the secret somewhere safe. It is shown only once and cannot be viewed again. If you lose it, you can rotate it later by editing the webhook. See "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Verify-webhook-signatures",
                    "children": [
                      {
                        "type": "text",
                        "value": "Verify webhook signatures"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": "."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Events that will trigger webhook: Select which events should be delivered to this endpoint. At least one event is required. Currently, only the `run.completed` event is available, so it is preselected by default and cannot be removed."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Enable this webhook: Whether the webhook is active. Enabled by default; disabled webhooks not called when"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Click Add webhook to save. Cypress Cloud will begin delivering the selected events to your endpoint."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Send a test event"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To confirm your endpoint is reachable and your verification logic works, use Send test on an enabled webhook. This delivers a synthetic `webhook.ping` event through the same signing and delivery pipeline as real events, so it exercises your signature verification exactly as a `run.completed` event would."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `webhook.ping` request body is:"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "{\n  \"message\": \"Webhook ping\"\n}"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Test events are delivered once and are not retried, regardless of the outcome. The resulting delivery appears in the webhook's delivery history like any other."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Manage webhooks"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Each webhook appears as a row in the Webhooks panel showing its URL, an enable/disable toggle, and the status of its most recent delivery (for example, Last delivery succeeded, Retrying, Last delivery failed, Delivering…, or Never triggered). Use the inline controls and the Options (⋯) menu to manage it:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Enable or disable: Toggle the switch on the row. A disabled webhook keeps its configuration but receives no deliveries."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Edit: Open the Options menu and select Edit to change the URL, events, or secret."
                  }
                ]
              },
              {
                "type": "list",
                "ordered": false,
                "start": null,
                "spread": false,
                "children": [
                  {
                    "type": "listItem",
                    "spread": false,
                    "checked": null,
                    "children": [
                      {
                        "type": "paragraph",
                        "children": [
                          {
                            "type": "text",
                            "value": "Generate new secret: Leaving the Secret field blank keeps the existing secret. To rotate it, enter a new value (at least 16 characters) or click Generate new secret. Copy the new secret and store it somewhere safe. It is shown only once. After you save, the previous secret no longer verifies requests, so update your endpoint to use the new value."
                          }
                        ]
                      }
                    ]
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Recent deliveries: Open the Options menu and select Recent deliveries to review delivery history. See "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Delivery-history-and-retries",
                    "children": [
                      {
                        "type": "text",
                        "value": "Delivery history and retries"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": "."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Delete: Open the Options menu and select Delete. This permanently removes the webhook and its delivery history. This cannot be undone."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A project can have at most 5 webhooks. When you reach the limit, the Add webhook button is disabled until you delete an existing webhook."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Events"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Currently only one event in the Cypress Cloud lifecycle triggers a webhook:"
          }
        ]
      },
      {
        "type": "table",
        "align": [
          null,
          null
        ],
        "children": [
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Event"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Description"
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`run.completed`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Sent when a Cypress Cloud run finished and resolves to one of the following states: `passed`, `failed`, `errored`, `timedOut`, or `cancelled`."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "There is also a special `webhook.ping` event that is only sent by the "
          },
          {
            "type": "link",
            "title": null,
            "url": "#Send-a-test-event",
            "children": [
              {
                "type": "text",
                "value": "Send a test event"
              }
            ]
          },
          {
            "type": "text",
            "value": " action. You cannot subscribe to it directly."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Payload"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Cypress Cloud sends a `POST` request whose body is the event payload as JSON. Metadata about the delivery travels in `X-Cypress-*` request headers rather than in the body."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Request headers"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Every delivery includes the following headers:"
          }
        ]
      },
      {
        "type": "table",
        "align": [
          null,
          null
        ],
        "children": [
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Header"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Description"
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`Content-Type`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Always `application/json`."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Event`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The event type, for example `run.completed`."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Event-Id`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Unique ID for the event. Stable across retries. Use it to deduplicate."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Event-Version`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The payload schema version, for example `1`."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Request-Id`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Unique ID for this individual delivery attempt. A new value on every retry."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Timestamp`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The time the request was sent, as a Unix timestamp in seconds."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Idempotency-Key`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Stable key for this event and webhook. Identical across retries of the same event."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`X-Cypress-Signature`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "HMAC-SHA256 signature of the payload. Only present when a signing secret is set. See "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "#Verify-webhook-signatures",
                    "children": [
                      {
                        "type": "text",
                        "value": "Verify webhook signatures"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": "."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Because `X-Cypress-Event-Id` (and `X-Cypress-Idempotency-Key`) stay constant across retries, your endpoint may receive the same event more than once. Treat delivery as at-least-once and make your handler idempotent by keying on `X-Cypress-Event-Id`."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "`run.completed` payload"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `run.completed` payload (version `1`) is a flat JSON object with the following fields:"
          }
        ]
      },
      {
        "type": "table",
        "align": [
          null,
          null,
          null
        ],
        "children": [
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Field"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Type"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Description"
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`runNumber`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The run's number in Cypress Cloud."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`runUrl`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Link to the run in Cypress Cloud."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`projectId`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/cloud/account-management/projects.md#Project-ID",
                    "children": [
                      {
                        "type": "text",
                        "value": "Project ID"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": " used for the run."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`projectName`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The project name, which can be chosen in your Cypress Cloud settings."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`status`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Run status: `passed`, `failed`, `errored`, `timedOut`, or `cancelled`."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`statusReason`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Human-readable explanation of the status."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`createdAt`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "ISO 8601 timestamp when the run started."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`completedAt`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "ISO 8601 timestamp when the run finished."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalDuration`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Total run duration in milliseconds."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalTests`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Total number of tests."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalPassed`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of passed tests."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalFailed`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of failed tests."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalPending`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of pending tests."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalSkipped`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of skipped tests."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`flakyTestCount`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of passing tests that failed at least one attempt and passed using "
                  },
                  {
                    "type": "link",
                    "title": null,
                    "url": "/llm/markdown/app/guides/test-retries.md",
                    "children": [
                      {
                        "type": "text",
                        "value": "retries"
                      }
                    ]
                  },
                  {
                    "type": "text",
                    "value": "."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`totalSpecs`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`number`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Number of spec files."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitSha`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The commit SHA the run was recorded against."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitBranch`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The branch name."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitMessage`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The commit message."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitAuthorName`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The commit author's name."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitAuthorEmail`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The commit author's email."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`commitUrl`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Link to the commit."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`ciProvider`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The detected CI provider, for example `circleci`."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`ciBuildId`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The CI build ID."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`ciUrl`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Link to the CI build."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`ciPullRequestId`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The pull request ID, when available."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`ciPullRequestUrl`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`null`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "Link to the pull request, when available."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`tags`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string[]`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The tags the run was recorded with (sorted)."
                  }
                ]
              }
            ]
          },
          {
            "type": "tableRow",
            "children": [
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`groups`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "`string[]`"
                  }
                ]
              },
              {
                "type": "tableCell",
                "children": [
                  {
                    "type": "text",
                    "value": "The run groups (sorted)."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Missing fields: If you are missing expected commit information or CI details, ensure the related environment variables are present in the context where Cypress executes. For example, when executing Cypress in a container, your "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/smart-orchestration/parallelization.md#CI-Build-ID-environment-variables-by-provider",
            "children": [
              {
                "type": "text",
                "value": "CI identifiers"
              }
            ]
          },
          {
            "type": "text",
            "value": " and related build information may need to be set explicitly."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Example `run.completed` request body"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "{\n  \"runNumber\": 42,\n  \"runUrl\": \"https://cloud.cypress.io/projects/my-project/runs/42\",\n  \"projectId\": \"my-project\",\n  \"projectName\": \"My Project\",\n  \"status\": \"passed\",\n  \"statusReason\": \"Run passed\",\n  \"createdAt\": \"2026-01-01T00:00:00.000Z\",\n  \"completedAt\": \"2026-01-01T00:05:00.000Z\",\n  \"totalDuration\": 300000,\n  \"totalTests\": 100,\n  \"totalPassed\": 95,\n  \"totalFailed\": 0,\n  \"totalPending\": 2,\n  \"totalSkipped\": 3,\n  \"flakyTestCount\": 0,\n  \"totalSpecs\": 4,\n  \"commitSha\": \"abc123\",\n  \"commitBranch\": \"main\",\n  \"commitMessage\": \"fix: something\",\n  \"commitAuthorName\": \"Ada Lovelace\",\n  \"commitAuthorEmail\": \"ada@example.com\",\n  \"commitUrl\": \"https://github.com/cypress-io/cypress-services/commit/abc123\",\n  \"ciProvider\": \"circleci\",\n  \"ciBuildId\": \"circleci-workflow-777\",\n  \"ciUrl\": \"https://circleci.com/gh/cypress-io/cypress-services/555\",\n  \"ciPullRequestId\": null,\n  \"ciPullRequestUrl\": null,\n  \"tags\": [\"canary\", \"nightly\"],\n  \"groups\": [\"chrome\", \"firefox\"]\n}"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Verify webhook signatures"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When you configure a signing secret, Cypress Cloud signs every request so your endpoint can confirm that a payload genuinely came from Cypress Cloud and was not altered in transit. We strongly recommend setting a signing secret for every webhook. Because your Payload URL is a publicly reachable endpoint, anyone who discovers it could send it forged requests; verifying the signature lets your handler reject anything that isn't authentically from Cypress Cloud."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The signing secret provides three things:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Authenticity: proof the request came from Cypress Cloud, not an impersonator."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Integrity: proof the payload was not tampered with, since any change invalidates the signature."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Replay protection: the signature covers a timestamp, so you can reject stale requests that are replayed later."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "A signing secret does not encrypt the payload. Use HTTPS when the payload must stay confidential. Over HTTP, anyone on the network path can still read the request body and headers. The HMAC still proves the request came from Cypress Cloud and was not modified, because the secret itself is never sent."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "How the signature is computed"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "When a secret is set, Cypress Cloud includes an `X-Cypress-Signature` header:"
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "X-Cypress-Signature: sha256=<hex-encoded HMAC>"
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The signature is an HMAC-SHA256, keyed with your signing secret, of the string `` `${timestamp}.${rawBody}` `` (the value of the `X-Cypress-Timestamp` header, a literal `.`, then the exact raw bytes of the request body). The result is hex-encoded and prefixed with `sha256=`."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To verify a request:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": true,
        "start": 1,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Read the `X-Cypress-Signature` and `X-Cypress-Timestamp` headers and the raw request body (before any JSON parsing; parsing and re-serializing can change the bytes and break verification)."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Optionally reject the request if the timestamp is too old (for example, more than five minutes) to guard against replay attacks."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Recompute `HMAC-SHA256(secret, \"${timestamp}.${rawBody}\")`, hex-encode it, and prefix `sha256=`."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Compare it to `X-Cypress-Signature` using a constant-time comparison."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If a webhook has no signing secret, Cypress Cloud still delivers events, but the `X-Cypress-Signature` header is omitted. Configure a secret to enable verification."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Verify a signature in your handler"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The following example handlers add a route to an existing Express or Flask app. They read the raw body, reject stale timestamps, recompute the HMAC, and compare it in constant time."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Node.js and Python examples"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Node.js"
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Python"
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "const crypto = require('crypto')\n\nconst SIGNING_SECRET = process.env.CYPRESS_WEBHOOK_SECRET\n\n// Register this route before express.json() or any other body parser.\n// Those parsers consume the body and would break signature verification.\napp.post(\n  '/receive-webhook',\n  express.raw({ type: 'application/json' }),\n  (req, res) => {\n    const signature = req.get('X-Cypress-Signature')\n    const timestamp = req.get('X-Cypress-Timestamp')\n    const rawBody = req.body // Buffer\n\n    if (!signature || !timestamp) {\n      return res.status(400).send('Missing signature headers')\n    }\n\n    // Reject stale requests to protect against replay attacks (5 minute window).\n    if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {\n      return res.status(400).send('Timestamp outside of tolerance')\n    }\n\n    const expected =\n      'sha256=' +\n      crypto\n        .createHmac('sha256', SIGNING_SECRET)\n        .update(`${timestamp}.${rawBody.toString('utf8')}`)\n        .digest('hex')\n\n    const valid =\n      signature.length === expected.length &&\n      crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))\n\n    if (!valid) {\n      return res.status(401).send('Invalid signature')\n    }\n\n    const event = JSON.parse(rawBody.toString('utf8'))\n    // ...handle the event...\n\n    res.status(200).send('ok')\n  }\n)"
      },
      {
        "type": "code",
        "lang": null,
        "meta": null,
        "value": "import hashlib\nimport hmac\nimport os\nimport time\n\nfrom flask import abort, request\n\nSIGNING_SECRET = os.environ[\"CYPRESS_WEBHOOK_SECRET\"].encode()\n\n\n@app.post(\"/receive-webhook\")\ndef receive_webhook():\n    signature = request.headers.get(\"X-Cypress-Signature\", \"\")\n    timestamp = request.headers.get(\"X-Cypress-Timestamp\", \"\")\n    # Bytes as received. Don't use request.json; parsing and re-serializing\n    # can change the body and break verification.\n    raw_body = request.get_data()\n\n    if not signature or not timestamp:\n        abort(400, \"Missing signature headers\")\n\n    # Reject stale requests to protect against replay attacks (5 minute window).\n    if abs(time.time() - int(timestamp)) > 300:\n        abort(400, \"Timestamp outside of tolerance\")\n\n    signed = f\"{timestamp}.\".encode() + raw_body\n    digest = hmac.new(SIGNING_SECRET, signed, hashlib.sha256).hexdigest()\n    expected = f\"sha256={digest}\"\n\n    if not hmac.compare_digest(signature, expected):\n        abort(401, \"Invalid signature\")\n\n    # event = json.loads(raw_body)\n    # ...handle the event...\n\n    return \"ok\", 200"
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Delivery history and retries"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Open the Options menu on a webhook and select Recent deliveries to review its delivery history. Cypress Cloud retains up to 100 deliveries per webhook, newest first. Each entry shows the event type and version, timestamps, and a status. Expand a delivery to inspect the full per-attempt request and response: headers, bodies, response status, and any error details."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Delivery statuses:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Delivered: The endpoint returned a success response."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Pending: The delivery is queued or in progress."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Retrying: An attempt failed and another is scheduled."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Failed. No more retries.: The delivery failed and will not be retried. Automatic retries are exhausted, the failure is not retryable (for example a `3xx` or a `4xx` other than `408` or `429`), or the event was a test (`webhook.ping`)."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "For your protection, sensitive request headers (such as `Authorization` and `Cookie`) are redacted in the stored delivery history."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Retry behavior"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "If a delivery fails, Cypress Cloud retries it until it succeeds or reaches 10 total attempts (the first attempt plus up to 9 retries), using an exponential backoff schedule with jitter. Cypress Cloud retries on network/transport errors and on HTTP `408`, `429`, and `5xx` responses. Other completed responses (`3xx` and other `4xx`) and blocked destinations are treated as permanent failures and are not retried. Test (`webhook.ping`) events are never retried."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "Each attempt is listed under that delivery in Recent deliveries. Expand the delivery to see Attempt 1, Attempt 2, and so on. Automatic retries are tagged Retry; a redelivery you trigger is tagged Manual retry."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To resend a failed or exhausted delivery yourself, expand it in the Recent deliveries dialog and choose Redeliver. A redelivery reuses the original payload and keeps the same `X-Cypress-Event-Id`, so your idempotency logic still recognizes it as the same event."
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Security"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "We recommend that you always use an `https://` Payload URL so payloads are encrypted in transit."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "In addition, Cypress Cloud applies several protections to webhook delivery:"
          }
        ]
      },
      {
        "type": "list",
        "ordered": false,
        "start": null,
        "spread": false,
        "children": [
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Endpoint restrictions: Destination URLs are resolved and validated before each delivery. Requests to private, loopback, and link-local addresses are blocked to prevent server-side request forgery (SSRF)."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "No redirects: Cypress Cloud does not follow HTTP redirects; the Payload URL must respond directly."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Timeouts and limits: Each attempt times out after 10 seconds, and only the first 8 KB of your response body is read and stored."
                  }
                ]
              }
            ]
          },
          {
            "type": "listItem",
            "spread": false,
            "checked": null,
            "children": [
              {
                "type": "paragraph",
                "children": [
                  {
                    "type": "text",
                    "value": "Secret storage: Signing secrets are encrypted at rest and are never returned by the Cypress Cloud API. A secret is shown only once, when you set it."
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "type": "heading",
        "depth": 2,
        "children": [
          {
            "type": "text",
            "value": "Troubleshooting"
          }
        ]
      },
      {
        "type": "heading",
        "depth": 3,
        "children": [
          {
            "type": "text",
            "value": "Run completed webhook fires too late"
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "The `run.completed` webhook is delivered when Cypress Cloud marks the run as complete. If you record in parallel or with multiple groups, Cypress Cloud waits for the "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/account-management/projects.md#Run-Completion-Delay",
            "children": [
              {
                "type": "text",
                "value": "Run Completion Delay"
              }
            ]
          },
          {
            "type": "text",
            "value": " (60 seconds by default) after the last known group finishes, in case more groups still join. That wait is what delays the webhook, because if all tests haven't been recorded yet, the final state of the run is not known."
          }
        ]
      },
      {
        "type": "paragraph",
        "children": [
          {
            "type": "text",
            "value": "To complete the run as soon as your expected groups have finished, call the "
          },
          {
            "type": "link",
            "title": null,
            "url": "/llm/markdown/cloud/features/smart-orchestration/parallelization.md#Run-Completion-API",
            "children": [
              {
                "type": "text",
                "value": "Run Completion API"
              }
            ]
          },
          {
            "type": "text",
            "value": ". Cypress Cloud then skips the remaining delay, and the webhook is delivered when in-progress groups finish."
          }
        ]
      }
    ]
  },
  "token_estimate": 3745
}