> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praxa.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Update a webhook endpoint

> Update an existing Praxa webhook URL, event filter, or enabled state with a strict non-empty request.

Update an existing Praxa webhook URL, event filter, or enabled state with a strict non-empty request.

<Info>
  **Availability:** Partner preview. **Required scopes:** `runs:write`, `runs:read`.
</Info>

## Authenticate safely

Create a disposable **personal workspace** API key with exactly `runs:write` and `runs:read`. Send it as `Authorization: Bearer $PRAXA_API_KEY`. A Gateway OAuth token, Supabase JWT, provider credential, or organization memory key is not interchangeable with this key.

The hosted playground sends the credential from your browser session to the documented API through the configured playground proxy. Use test data, never share the key, and revoke it when the check ends.

## Request fields

<ParamField path="endpointId" type="string" required>
  endpointId path parameter.
</ParamField>

<ParamField body="url" type="string">
  url request field.
</ParamField>

<ParamField body="event_types" type="array<run.accepted | run.started | run.progress | approval.required | approval.resolved | run.completed | run.failed | run.cancelled>">
  event\_types request field.
</ParamField>

<ParamField body="description" type="string | null">
  description request field.
</ParamField>

<ParamField body="status" type="active | disabled">
  status request field.
</ParamField>

## Runnable request examples

<CodeGroup>
  ```bash cURL theme={null}
  curl --fail-with-body -X PATCH 'https://api.praxa.io/v1/webhooks/endpoint-demo-0001' \
    -H "Authorization: Bearer $PRAXA_API_KEY" \
    -H "Content-Type: application/json" \
    --data '{
    "url": "https://example.com/praxa"
  }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://api.praxa.io/v1/webhooks/endpoint-demo-0001", {
    "method": "PATCH",
    "headers": {
      "Authorization": `Bearer ${process.env.PRAXA_API_KEY}`,
      "Content-Type": "application/json"
    },
    "body": JSON.stringify({
      "url": "https://example.com/praxa"
    })
  });
  const text = await response.text();
  if (!response.ok) throw new Error(`${response.status}: ${text}`);
  console.log(text ? JSON.parse(text) : { status: response.status });
  ```

  ```python Python theme={null}
  import json
  import os
  from urllib import error, request

  payload = json.dumps({
    "url": "https://example.com/praxa"
  }).encode()

  req = request.Request(
      "https://api.praxa.io/v1/webhooks/endpoint-demo-0001",
      method="PATCH",
      headers={
        "Authorization": f"Bearer {os.environ['PRAXA_API_KEY']}",
        "Content-Type": "application/json"
      },
      data=payload,
  )
  try:
      with request.urlopen(req, timeout=30) as response:
          text = response.read().decode()
          print(json.loads(text) if text else {"status": response.status})
  except error.HTTPError as exc:
      raise RuntimeError(f"{exc.code}: {exc.read().decode()}") from exc
  ```
</CodeGroup>

## What success means

A `200` response is the updated endpoint metadata; no signing secret is returned.

## Successful response

**200** — Updated endpoint metadata.

<ResponseField name="apiVersion" type="v1" required>
  apiVersion response field.
</ResponseField>

<ResponseField name="id" type="string" required>
  id response field.
</ResponseField>

<ResponseField name="url" type="string" required>
  url response field.
</ResponseField>

<ResponseField name="event_types" type="array<run.accepted | run.started | run.progress | approval.required | approval.resolved | run.completed | run.failed | run.cancelled>" required>
  event\_types response field.
</ResponseField>

<ResponseField name="description" type="string">
  description response field.
</ResponseField>

<ResponseField name="status" type="active | disabled" required>
  status response field.
</ResponseField>

<ResponseField name="createdAt" type="string" required>
  createdAt response field.
</ResponseField>

<ResponseField name="updatedAt" type="string" required>
  updatedAt response field.
</ResponseField>

<ResponseExample>
  ```json 200 theme={null}
  {
    "apiVersion": "v1",
    "id": "018f0000-0000-7000-8000-000000000001",
    "url": "https://example.com/praxa",
    "event_types": [
      "run.accepted"
    ],
    "status": "active",
    "createdAt": "2026-08-13T12:00:00.000Z",
    "updatedAt": "2026-08-13T12:00:00.000Z"
  }
  ```
</ResponseExample>

## Handle failures

| Response                    | Meaning                                                             | Safe action                                                                         |
| --------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `400 invalid_request`       | The method, path, headers, query, or body failed strict validation. | Correct the request; do not retry unchanged input.                                  |
| `401 authentication_failed` | The bearer key is missing, malformed, expired, or revoked.          | Stop and replace the key through the authenticated console.                         |
| `403 authorization_failed`  | The authenticated key lacks scope or tenant authority.              | Request only the missing least-privilege scope; never substitute another tenant ID. |
| `429 rate_limited`          | The principal exceeded a bounded rate.                              | Honor `retryAfterMs` or `Retry-After`, add jitter, and cap attempts.                |
| retryable `5xx`             | The server could not confirm a final response.                      | Reconcile reads or replay the exact keyed mutation before creating new work.        |

```json Example problem theme={null}
{
  "type": "https://docs.praxa.io/problems/authorization-failed",
  "title": "Authorization failed",
  "status": 403,
  "code": "authorization_failed",
  "detail": "The API key does not grant the required scope.",
  "retryable": false
}
```

## Verify the result

1. Read the endpoint list and confirm the changed fields.
2. Trigger only an event allowed by the new filter.
3. Confirm a foreign endpoint ID fails closed.

## Retry, cleanup, and production use

* Treat `401`, `403`, and `409` as authority or state signals, not generic retry prompts.
* For `429` or retryable 5xx responses, follow server retry guidance and keep a bounded attempt budget.
* Move the request into a trusted application backend before production; never ship the Praxa key in browser or mobile code.
* Revoke the disposable key, disable test webhooks, and erase disposable candidate data after validation.

Continue with [API authentication](/api-playground/authentication), the [failure and retry guide](/api-playground/errors), and the [end-to-end coverage matrix](/api-playground/coverage-and-testing).
