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

# Webhooks API: Register and Manage Real-Time Event Listeners

> Register webhook endpoints to receive real-time HTTP POST notifications from Google when records, users, or integrations change in your workspace.

Webhooks let your external systems react to activity in your Google workspace the moment it happens, without polling. When an event occurs — a record is created, a user is removed, an integration goes live — Google sends an HTTP POST request with a structured JSON payload to the URL you register. This makes it straightforward to build automation pipelines, audit logs, or live dashboards that stay in sync with your workspace in real time.

***

## Available Events

The following events can trigger webhook deliveries to your registered endpoints.

| Event                      | Triggered When                     |
| -------------------------- | ---------------------------------- |
| `record.created`           | A new data record is created       |
| `record.updated`           | A data record is modified          |
| `record.deleted`           | A data record is deleted           |
| `user.invited`             | A user is invited to the workspace |
| `user.removed`             | A user is removed                  |
| `integration.connected`    | An integration is connected        |
| `integration.disconnected` | An integration is removed          |

***

## Webhook Payload

Every webhook delivery is a `POST` request to your registered URL with a `Content-Type: application/json` header and a consistent JSON body structure. The `data` object reflects the resource that triggered the event.

### Example Payload

```json theme={null}
{
  "event": "record.created",
  "timestamp": "2024-03-10T14:22:00Z",
  "workspace_id": "ws_xyz789",
  "data": {
    "id": "rec_abc123",
    "name": "New Record",
    "type": "document",
    "created_by": "usr_abc123"
  }
}
```

### Payload Fields

<ResponseField name="event" type="string">
  The event type that triggered this delivery (e.g., `record.created`).
</ResponseField>

<ResponseField name="timestamp" type="string">
  ISO 8601 timestamp of when the event occurred in the workspace.
</ResponseField>

<ResponseField name="workspace_id" type="string">
  The unique identifier of the workspace where the event took place.
</ResponseField>

<ResponseField name="data" type="object">
  The resource object associated with the event. The shape of this object varies by event type — record events include record fields, user events include user fields, and so on.
</ResponseField>

<Info>
  Google expects your endpoint to respond with an HTTP `2xx` status code within **5 seconds**. If the delivery times out or receives a non-2xx response, it will be retried up to three times with exponential backoff.
</Info>

***

## Register Webhook

Register a new endpoint URL to start receiving event notifications for your workspace.

**`POST https://api.google.com/v1/webhooks`**

### Body Parameters

<ParamField body="url" type="string" required>
  The publicly accessible HTTPS URL that Google should send event payloads to. Must begin with `https://`.
</ParamField>

<ParamField body="events" type="array" required>
  An array of event type strings to subscribe to. Use `["*"]` to subscribe to all events. See the [Available Events](#available-events) table for valid values.
</ParamField>

<ParamField body="secret" type="string">
  An optional secret string used to generate an HMAC-SHA256 signature for each delivery. When provided, Google includes an `X-Google-Signature` header with every request so you can verify authenticity. See [Verifying Webhook Signatures](#verifying-webhook-signatures) for implementation details.
</ParamField>

### Example Request

```bash theme={null}
curl -X POST "https://api.google.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourapp.com/webhooks/google",
    "events": ["record.created", "record.updated", "user.invited"],
    "secret": "your_signing_secret"
  }'
```

### Example Response

```json theme={null}
{
  "success": true,
  "data": {
    "id": "wh_abc123",
    "url": "https://yourapp.com/webhooks/google",
    "events": ["record.created", "record.updated", "user.invited"],
    "status": "active",
    "created_at": "2024-06-01T09:00:00Z"
  }
}
```

***

## List Webhooks

Retrieve all webhook registrations for your workspace.

**`GET https://api.google.com/v1/webhooks`**

### Example Request

```bash theme={null}
curl -X GET "https://api.google.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Example Response

```json theme={null}
{
  "success": true,
  "data": [
    {
      "id": "wh_abc123",
      "url": "https://yourapp.com/webhooks/google",
      "events": ["record.created", "record.updated", "user.invited"],
      "status": "active",
      "created_at": "2024-06-01T09:00:00Z"
    },
    {
      "id": "wh_def456",
      "url": "https://yourapp.com/webhooks/audit",
      "events": ["user.removed", "integration.disconnected"],
      "status": "active",
      "created_at": "2024-06-02T11:30:00Z"
    }
  ],
  "meta": { "total": 2 }
}
```

***

## Delete Webhook

Remove a registered webhook. Google will immediately stop delivering events to the associated URL.

**`DELETE https://api.google.com/v1/webhooks/:id`**

### Path Parameters

<ParamField path="id" type="string" required>
  The unique identifier of the webhook to delete (e.g., `wh_abc123`).
</ParamField>

### Example Request

```bash theme={null}
curl -X DELETE "https://api.google.com/v1/webhooks/wh_abc123" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

A successful deletion returns HTTP `204 No Content` with an empty body.

***

## Verifying Webhook Signatures

When you register a webhook with a `secret`, Google includes an `X-Google-Signature` header with every request. The value is a SHA-256 HMAC of the raw request body, prefixed with `sha256=`. Verifying this signature ensures the payload genuinely came from Google and has not been tampered with.

### Verification Example (Node.js)

```javascript theme={null}
const crypto = require('crypto');
const express = require('express');
const app = express();

// Use the raw body buffer for signature verification — do NOT use express.json()
// middleware before this route, as JSON parsing discards whitespace and may
// produce a different byte sequence than the original payload.
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-google-signature'];
  const rawBody = req.body; // Buffer containing the raw request bytes

  const expected = crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(rawBody)
    .digest('hex');

  const expectedSig = Buffer.from(`sha256=${expected}`);
  const receivedSig = Buffer.from(sig || '');

  // Use timingSafeEqual to prevent timing attacks
  if (
    expectedSig.length !== receivedSig.length ||
    !crypto.timingSafeEqual(expectedSig, receivedSig)
  ) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(rawBody);
  // Process the event
  console.log('Verified event:', event.event);
  res.status(200).send('OK');
});
```

<Note>
  Always compute the HMAC over the **raw request body bytes** — not a re-serialized JSON object. Parsing and re-stringifying the payload can change whitespace and key ordering, producing a different byte sequence and causing signature validation to fail. Use `express.raw()` (or equivalent) to capture the original bytes before any JSON parsing occurs.
</Note>

<Tip>
  While developing locally, use a tunneling tool like [ngrok](https://ngrok.com) to expose your local server to the internet and receive live webhook deliveries. Run `ngrok http 3000` to get a public HTTPS URL, then register that URL as your webhook endpoint. This lets you iterate on your handler without deploying to a staging environment.
</Tip>

***

## Error Reference

<AccordionGroup>
  <Accordion title="400 Bad Request">
    The request body is missing required fields (`url` or `events`), the URL is not a valid HTTPS address, or the events array contains unrecognized event types.
  </Accordion>

  <Accordion title="401 Unauthorized">
    Your API key is missing or invalid. Include a valid Bearer token in the `Authorization` header.
  </Accordion>

  <Accordion title="404 Not Found">
    No webhook exists with the specified `id`. Use the List Webhooks endpoint to confirm the correct identifier.
  </Accordion>

  <Accordion title="422 Unprocessable Entity">
    The request is syntactically valid but the provided `url` is unreachable or returns non-2xx responses during validation.
  </Accordion>

  <Accordion title="429 Too Many Requests">
    You have exceeded the webhook registration limit for your plan. Review your existing webhooks and remove any that are no longer needed.
  </Accordion>
</AccordionGroup>
