Skip to main content
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.
EventTriggered When
record.createdA new data record is created
record.updatedA data record is modified
record.deletedA data record is deleted
user.invitedA user is invited to the workspace
user.removedA user is removed
integration.connectedAn integration is connected
integration.disconnectedAn 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

{
  "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

event
string
The event type that triggered this delivery (e.g., record.created).
timestamp
string
ISO 8601 timestamp of when the event occurred in the workspace.
workspace_id
string
The unique identifier of the workspace where the event took place.
data
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.
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.

Register Webhook

Register a new endpoint URL to start receiving event notifications for your workspace. POST https://api.google.com/v1/webhooks

Body Parameters

url
string
required
The publicly accessible HTTPS URL that Google should send event payloads to. Must begin with https://.
events
array
required
An array of event type strings to subscribe to. Use ["*"] to subscribe to all events. See the Available Events table for valid values.
secret
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 for implementation details.

Example Request

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

{
  "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

curl -X GET "https://api.google.com/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

{
  "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

id
string
required
The unique identifier of the webhook to delete (e.g., wh_abc123).

Example Request

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)

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');
});
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.
While developing locally, use a tunneling tool like ngrok 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.

Error Reference

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.
Your API key is missing or invalid. Include a valid Bearer token in the Authorization header.
No webhook exists with the specified id. Use the List Webhooks endpoint to confirm the correct identifier.
The request is syntactically valid but the provided url is unreachable or returns non-2xx responses during validation.
You have exceeded the webhook registration limit for your plan. Review your existing webhooks and remove any that are no longer needed.