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

# Update webhook

> Update the URL, event types, or active state of an existing webhook

<blockquote className="agent-llms-directive">
  For the complete documentation index, see <a href="/llms.txt">llms.txt</a>.
</blockquote>

<Callout icon="circle-check" color="#16a34a">
  **Free** - does not consume credits
</Callout>

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH https://xquik.com/api/v1/webhooks/15 \
    -H "x-api-key: xq_YOUR_KEY_HERE" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://new-server.com/webhook",
      "eventTypes": ["tweet.new"],
      "isActive": false
    }' | jq '{
      webhook_id: .id,
      url,
      event_types: .eventTypes,
      is_active: .isActive,
      delivery_status: .deliveryStatus,
      consecutive_failures: .consecutiveFailures,
      failure_hard_cap: .failureHardCap,
      test_endpoint: ("/api/v1/webhooks/" + .id + "/test"),
      resume_endpoint: ("/api/v1/webhooks/" + .id + "/resume"),
      deliveries_endpoint: ("/api/v1/webhooks/" + .id + "/deliveries")
    }'
  ```

  ```javascript Node.js theme={null}
  const response = await fetch("https://xquik.com/api/v1/webhooks/15", {
    method: "PATCH",
    headers: {
      "x-api-key": "xq_YOUR_KEY_HERE",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://new-server.com/webhook",
      eventTypes: ["tweet.new"],
      isActive: false,
    }),
  });
  const webhook = await response.json();
  const updateHandoff = {
    webhook_id: webhook.id,
    url: webhook.url,
    event_types: webhook.eventTypes,
    is_active: webhook.isActive,
    delivery_status: webhook.deliveryStatus,
    consecutive_failures: webhook.consecutiveFailures,
    failure_hard_cap: webhook.failureHardCap,
    test_endpoint: `/api/v1/webhooks/${webhook.id}/test`,
    resume_endpoint: `/api/v1/webhooks/${webhook.id}/resume`,
    deliveries_endpoint: `/api/v1/webhooks/${webhook.id}/deliveries`,
  };
  ```

  ```python Python theme={null}
  import requests

  response = requests.patch(
      "https://xquik.com/api/v1/webhooks/15",
      headers={"x-api-key": "xq_YOUR_KEY_HERE"},
      json={
          "url": "https://new-server.com/webhook",
          "eventTypes": ["tweet.new"],
          "isActive": False,
      },
  )
  webhook = response.json()
  update_handoff = {
      "webhook_id": webhook["id"],
      "url": webhook["url"],
      "event_types": webhook["eventTypes"],
      "is_active": webhook["isActive"],
      "delivery_status": webhook["deliveryStatus"],
      "consecutive_failures": webhook["consecutiveFailures"],
      "failure_hard_cap": webhook["failureHardCap"],
      "test_endpoint": f"/api/v1/webhooks/{webhook['id']}/test",
      "resume_endpoint": f"/api/v1/webhooks/{webhook['id']}/resume",
      "deliveries_endpoint": f"/api/v1/webhooks/{webhook['id']}/deliveries",
  }
  ```

  ```go Go theme={null}
  package main

  import (
    "bytes"
    "encoding/json"
    "log"
    "net/http"
  )

  type Webhook struct {
    ConsecutiveFailures int      `json:"consecutiveFailures"`
    DeliveryStatus      string   `json:"deliveryStatus"`
    EventTypes          []string `json:"eventTypes"`
    FailureHardCap      int      `json:"failureHardCap"`
    ID                  string   `json:"id"`
    IsActive            bool     `json:"isActive"`
    URL                 string   `json:"url"`
  }

  type UpdateHandoff struct {
    ConsecutiveFailures int      `json:"consecutive_failures"`
    DeliveriesEndpoint string   `json:"deliveries_endpoint"`
    DeliveryStatus     string   `json:"delivery_status"`
    EventTypes         []string `json:"event_types"`
    FailureHardCap     int      `json:"failure_hard_cap"`
    IsActive           bool     `json:"is_active"`
    ResumeEndpoint     string   `json:"resume_endpoint"`
    TestEndpoint       string   `json:"test_endpoint"`
    URL                string   `json:"url"`
    WebhookID          string   `json:"webhook_id"`
  }

  func main() {
    payload := map[string]interface{}{
      "url":        "https://new-server.com/webhook",
      "eventTypes": []string{"tweet.new"},
      "isActive":   false,
    }
    body, err := json.Marshal(payload)
    if err != nil {
      log.Fatal(err)
    }

    req, err := http.NewRequest("PATCH", "https://xquik.com/api/v1/webhooks/15", bytes.NewReader(body))
    if err != nil {
      log.Fatal(err)
    }
    req.Header.Set("x-api-key", "xq_YOUR_KEY_HERE")
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
      log.Fatal(err)
    }
    defer resp.Body.Close()

    var webhook Webhook
    if err := json.NewDecoder(resp.Body).Decode(&webhook); err != nil {
      log.Fatal(err)
    }
    handoff := UpdateHandoff{
      ConsecutiveFailures: webhook.ConsecutiveFailures,
      DeliveriesEndpoint: "/api/v1/webhooks/" + webhook.ID + "/deliveries",
      DeliveryStatus:     webhook.DeliveryStatus,
      EventTypes:         webhook.EventTypes,
      FailureHardCap:     webhook.FailureHardCap,
      IsActive:           webhook.IsActive,
      ResumeEndpoint:     "/api/v1/webhooks/" + webhook.ID + "/resume",
      TestEndpoint:       "/api/v1/webhooks/" + webhook.ID + "/test",
      URL:                webhook.URL,
      WebhookID:          webhook.ID,
    }
    _ = handoff
  }
  ```
</CodeGroup>

These snippets shape a reconfiguration row. Store the current webhook
configuration with its test and delivery-log endpoints instead of printing the
full update response.

## Path parameters

<ParamField path="id" type="string" required>
  The webhook ID to update.
</ParamField>

## Headers

<ParamField header="x-api-key" type="string" required>
  Your API key. This endpoint also accepts session cookie authentication.
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Must be `application/json`.
</ParamField>

## Body

At least 1 field is required.

<ParamField body="url" type="string">
  New HTTPS endpoint URL. HTTP URLs are rejected.
</ParamField>

<ParamField body="eventTypes" type="string[]">
  Updated event types to subscribe to. Replaces the existing list. At least 1
  required when provided. Use any valid account monitor event type listed below.
  Keyword monitor webhooks should stay on `tweet.*` event types. Account monitor
  webhooks can use both `tweet.*` and `profile.*` event types.
</ParamField>

## Valid event types

Valid types: `tweet.new`, `tweet.quote`, `tweet.reply`, `tweet.retweet`,
`tweet.media`, `tweet.link`, `tweet.poll`, `tweet.mention`, `tweet.hashtag`,
`tweet.longform`, `profile.avatar.changed`, `profile.banner.changed`,
`profile.name.changed`, `profile.username.changed`, `profile.bio.changed`,
`profile.location.changed`, `profile.url.changed`, `profile.verified.changed`,
`profile.protected.changed`, `profile.pinned_tweet.changed`,
`profile.unavailable.changed`.

<CardGroup cols={2}>
  <Card title="tweet.new" icon="bell">
    Original tweet from an account monitor or matching keyword monitor. Use for
    new posts that are not replies, quotes, or retweets.
  </Card>

  <Card title="tweet.quote" icon="quote">
    Quote tweet from an account monitor or matching keyword monitor. Keep this
    only when downstream systems handle quote payloads.
  </Card>

  <Card title="tweet.reply" icon="message-circle">
    Reply from an account monitor or matching keyword monitor. Keep this when
    reply alerts or support routing should continue.
  </Card>

  <Card title="tweet.retweet" icon="repeat-2">
    Retweet from an account monitor or matching keyword monitor. Keep this when
    repost activity should keep triggering deliveries.
  </Card>
</CardGroup>

<Note>
  `webhook.test` is generated only by the [Test Webhook](/api-reference/webhooks/test) endpoint. It cannot be added to a webhook subscription.
</Note>

<ParamField body="isActive" type="boolean">
  Set to `false` to pause deliveries. Set to `true` to reactivate a paused
  webhook and reset `consecutiveFailures`. When `deliveryStatus` is
  `needs_attention`, use [Resume Webhook](/api-reference/webhooks/resume) so the
  receiver must pass a signed test first.
</ParamField>

## Response

<Tabs>
  <Tab title="200 OK">
    <ResponseField name="id" type="string">
      Unique webhook identifier.
    </ResponseField>

    <ResponseField name="url" type="string">
      The current delivery endpoint URL.
    </ResponseField>

    <ResponseField name="eventTypes" type="string[]">
      Event types this webhook is subscribed to.
    </ResponseField>

    <ResponseField name="isActive" type="boolean">
      Whether the webhook is currently active.
    </ResponseField>

    <ResponseField name="consecutiveFailures" type="number">
      Consecutive delivery failures recorded for this webhook.
    </ResponseField>

    <ResponseField name="deliveryStatus" type="string">
      `active`, `paused`, or `needs_attention`.
    </ResponseField>

    <ResponseField name="failureHardCap" type="number">
      Failure count where the webhook needs attention before resuming.
    </ResponseField>

    <ResponseField name="createdAt" type="string">
      ISO 8601 creation timestamp.
    </ResponseField>

    ```json theme={null}
    {
      "id": "15",
      "url": "https://new-server.com/webhook",
      "eventTypes": ["tweet.new"],
      "isActive": false,
      "consecutiveFailures": 0,
      "deliveryStatus": "paused",
      "failureHardCap": 200,
      "createdAt": "2026-02-24T10:30:00.000Z"
    }
    ```
  </Tab>

  <Tab title="401 Unauthenticated">
    ```json theme={null}
    { "error": "unauthenticated" }
    ```

    Missing or invalid API key / session cookie.
  </Tab>

  <Tab title="400 Invalid Input">
    ```json theme={null}
    { "error": "invalid_input" }
    ```

    Invalid URL (must be HTTPS), empty `eventTypes`, or no fields provided.

    ```json theme={null}
    { "error": "invalid_id" }
    ```

    The provided webhook ID is not a valid format.
  </Tab>

  <Tab title="404 Not Found">
    ```json theme={null}
    { "error": "not_found" }
    ```

    No webhook exists with this ID, or it belongs to a different account.
  </Tab>

  <Tab title="429 Rate Limited">
    ```json theme={null}
    { "error": "rate_limit_exceeded", "message": "Too many requests. Try again later.", "retryAfter": 60 }
    ```

    Too many requests. Wait for the `Retry-After` header before retrying.
  </Tab>
</Tabs>

## Reconfiguration handoff

Use this endpoint when a receiver URL changes, an event filter changes, or an
operator needs to pause or resume webhook delivery without creating a new
endpoint.

<CardGroup cols={2}>
  <Card title="Updated Inventory" icon="clipboard-check">
    Store returned `id`, `url`, `eventTypes`, `isActive`, `deliveryStatus`,
    `consecutiveFailures`, `failureHardCap`, and `createdAt` as the current
    webhook configuration.
  </Card>

  <Card title="URL Change" icon="link">
    After changing `url`, run [Test Webhook](/api-reference/webhooks/test) before
    expecting production monitor events at the new receiver.
  </Card>

  <Card title="Event Filter" icon="funnel">
    `eventTypes` replaces the previous list. Keep it aligned with account or
    keyword monitor event types.
  </Card>

  <Card title="Pause Delivery" icon="toggle-left">
    `isActive: false` stops future deliveries. Existing stored events and
    delivery records remain available.
  </Card>

  <Card title="Resume Delivery" icon="toggle-right">
    `isActive: true` resumes delivery for matching future monitor events. Test
    the receiver after resuming. Use
    [Resume Webhook](/api-reference/webhooks/resume) when the receiver needs a
    signed test gate first.
  </Card>

  <Card title="Signing Secret" icon="shield-check">
    This endpoint does not rotate or return `secret`. Keep using the secret from
    [Create Webhook](/api-reference/webhooks/create) for signature verification.
  </Card>

  <Card title="Delivery check" icon="activity">
    After the signed test passes, use
    [List Deliveries](/api-reference/webhooks/deliveries) if production monitor
    events still miss the receiver. Check `status`, `attempts`,
    `lastStatusCode`, `lastError`, `createdAt`, and `deliveredAt`.
  </Card>

  <Card title="Event join" icon="link">
    Use delivery `streamEventId` as the `{id}` for
    [Get Event](/api-reference/events/get). Store `monitorId`, `monitorType`,
    `type`, `occurredAt`, and `data` with the reconfiguration incident.
  </Card>
</CardGroup>

<Note>
  This endpoint supports **dual authentication**: API key (`x-api-key` header) or session cookie from the dashboard.

  **Related:** [List Webhooks](/api-reference/webhooks/list) · [Test Webhook](/api-reference/webhooks/test) · [Resume Webhook](/api-reference/webhooks/resume) · [List Deliveries](/api-reference/webhooks/deliveries) · [Get Event](/api-reference/events/get) · [Delete Webhook](/api-reference/webhooks/delete)
</Note>
