Skip to content
Blog / Appwrite Webhooks: triggering events the right way
4 min

Appwrite Webhooks: triggering events the right way

Learn how to configure Appwrite Webhooks, select the right events, verify payloads with HMAC-SHA1, and build reliable real-world integrations.

Webhooks are the simplest way to react to things happening in your Appwrite project without polling. A user signs up. A file gets uploaded. A database row is updated. Appwrite fires an HTTP POST to a URL you control, and your server handles it.

The mechanics are straightforward, but there are details worth getting right: which events to subscribe to, how to verify that a request actually came from Appwrite, and how to structure your handler to handle retries gracefully.

Setting up a webhook

Webhooks are configured at the project level in the Appwrite Console:

  1. Open your project and go to Settings.
  2. Click Webhooks in the sidebar.
  3. Click Add Webhook.
  4. Give it a name, enter your endpoint URL, and select the events you want to subscribe to.
  5. Optionally, enable HTTP Basic Authentication to add an extra credential layer on your endpoint.
  6. Click Create.

That's it. Appwrite will now send a POST request to your URL every time one of the selected events fires.

You can also configure webhooks to send requests with a custom HTTP signature for verification, covered in the security section below.

Choosing events

Appwrite's event system covers everything that happens in your project. Events are grouped by resource type:

  • Authentication events
    NameDescription
    teams.*
    This event triggers on any teams event. Returns Team Object
    teams.*.create
    This event triggers when a team is created. Returns Team Object
    teams.*.delete
    This event triggers when a team is deleted. Returns Team Object
    teams.*.memberships.*
    This event triggers on any team memberships event. Returns Membership Object
    teams.*.memberships.*.create
    This event triggers when a membership is created. Returns Membership Object
    teams.*.memberships.*.delete
    This event triggers when a membership is deleted. Returns Membership Object
    teams.*.memberships.*.update
    This event triggers when a membership is updated. Returns Membership Object
    teams.*.memberships.*.update.status
    This event triggers when a team memberships status is updated. Returns Membership Object
    teams.*.update
    This event triggers when a team is updated. Returns Team Object
    teams.*.update.prefs
    This event triggers when a team's preferences are updated. Returns Team Object
    users.*
    This event triggers on any user's event. Returns User Object
    users.*.create
    This event triggers when a user is created. Returns User Object
    users.*.delete
    This event triggers when a user is deleted. Returns User Object
    users.*.recovery.*
    This event triggers on any user's recovery token event. Returns Token Object
    users.*.recovery.*.create
    This event triggers when a recovery token for a user is created. Returns Token Object
    users.*.recovery.*.update
    This event triggers when a recovery token for a user is validated. Returns Token Object
    users.*.sessions.*
    This event triggers on any user's sessions event. Returns Session Object
    users.*.sessions.*.create
    This event triggers when a session for a user is created. Returns Session Object
    users.*.sessions.*.delete
    This event triggers when a session for a user is deleted. Returns Session Object
    users.*.update
    This event triggers when a user is updated. Returns User Object
    users.*.update.email
    This event triggers when a user's email address is updated. Returns User Object
    users.*.update.name
    This event triggers when a user's name is updated. Returns User Object
    users.*.update.password
    This event triggers when a user's password is updated. Returns User Object
    users.*.update.prefs
    This event triggers when a user's preferences is updated. Returns User Object
    users.*.update.status
    This event triggers when a user's status is updated. Returns User Object
    users.*.verification.*
    This event triggers on any user's verification token event. Returns Token Object
    users.*.verification.*.create
    This event triggers when a verification token for a user is created. Returns Token Object
    users.*.verification.*.update
    This event triggers when a verification token for a user is validated. Returns Token Object
  • Databases events
    NameDescription
    tablesdb.*
    This event triggers on any database event. Returns Database Object
    tablesdb.*.tables.*
    This event triggers on any table event. Returns Table Object
    tablesdb.*.tables.*.columns.*
    This event triggers on any columns event. Returns Column Object
    tablesdb.*.tables.*.columns.*.create
    This event triggers when a column is created. Returns Column Object
    tablesdb.*.tables.*.columns.*.update
    This event triggers when a column is updated. Returns Column Object
    tablesdb.*.tables.*.columns.*.delete
    This event triggers when a column is deleted. Returns Column Object
    tablesdb.*.tables.*.create
    This event triggers when a table is created. Returns Table Object
    tablesdb.*.tables.*.delete
    This event triggers when a table is deleted. Returns Table Object
    tablesdb.*.tables.*.rows.*
    This event triggers on any rows event. Returns Row Object
    tablesdb.*.tables.*.rows.*.create
    This event triggers when a row is created. Returns Row Object
    tablesdb.*.tables.*.rows.*.delete
    This event triggers when a row is deleted. Returns Row Object
    tablesdb.*.tables.*.rows.*.update
    This event triggers when a row is updated. Returns Row Object
    tablesdb.*.tables.*.rows.*.upsert
    This event triggers when a row is upserted. Returns Row Object
    tablesdb.*.tables.*.indexes.*
    This event triggers on any indexes event. Returns Index Object
    tablesdb.*.tables.*.indexes.*.create
    This event triggers when an index is created. Returns Index Object
    tablesdb.*.tables.*.indexes.*.update
    This event triggers when an index is updated. Returns Index Object
    tablesdb.*.tables.*.indexes.*.delete
    This event triggers when an index is deleted. Returns Index Object
    tablesdb.*.tables.*.update
    This event triggers when a table is updated. Returns Table Object
    tablesdb.*.create
    This event triggers when a database is created. Returns Database Object
    tablesdb.*.delete
    This event triggers when a database is deleted. Returns Database Object
    tablesdb.*.update
    This event triggers when a database is updated. Returns Database Object
  • Storage events
    NameDescription
    buckets.*
    This event triggers on any buckets event. Returns Bucket Object
    buckets.*.create
    This event triggers when a bucket is created. Returns Bucket Object
    buckets.*.delete
    This event triggers when a bucket is deleted. Returns Bucket Object
    buckets.*.files.*
    This event triggers on any files event. Returns File Object
    buckets.*.files.*.create
    Since the Appwrite SDK chunks files in 5MB increments, this event will trigger for each 5MB chunk. A file is fully uploaded when chunksTotal equals chunksUploaded. Returns File Object
    buckets.*.files.*.delete
    This event triggers when a file is deleted. Returns File Object
    buckets.*.files.*.update
    This event triggers when a file is updated. Returns File Object
    buckets.*.update
    This event triggers when a bucket is updated. Returns Bucket Object
  • Functions events
    NameDescription
    functions.*
    This event triggers on any functions event. Returns Function Object
    functions.*.create
    This event triggers when a function is created. Returns Function Object
    functions.*.delete
    This event triggers when a function is deleted. Returns Function Object
    functions.*.deployments.*
    This event triggers on any deployments event. Returns Deployment Object
    functions.*.deployments.*.create
    This event triggers when a deployment is created. Returns Deployment Object
    functions.*.deployments.*.delete
    This event triggers when a deployment is deleted. Returns Deployment Object
    functions.*.deployments.*.update
    This event triggers when a deployment is updated. Returns Deployment Object
    functions.*.executions.*
    This event triggers on any executions event. Returns Execution Object
    functions.*.executions.*.create
    This event triggers when an execution is created. Returns Execution Object
    functions.*.executions.*.delete
    This event triggers when an execution is deleted. Returns Execution Object
    functions.*.executions.*.update
    This event triggers when an execution is updated. Returns Execution Object
    functions.*.update
    This event triggers when a function is updated. Returns Function Object
  • Messaging events
    NameDescription
    providers.*
    This event triggers on any providers event. Returns Provider Object
    providers.*.create
    This event triggers when a provider is created. Returns Provider Object
    providers.*.delete
    This event triggers when a provider is deleted. Returns Provider Object
    providers.*.update
    This event triggers when a provider is updated. Returns Provider Object
    topics.*
    This event triggers on any topic event. Returns Topic Object
    topics.*.create
    This event triggers when a topic is created. Returns Topic Object
    topics.*.delete
    This event triggers when a topic is deleted. Returns Topic Object
    topics.*.update
    This event triggers when a topic is updated. Returns Topic Object
    topics.*.subscribers.*.create
    This event triggers when a subscriber to a topic is created. Returns Topic Object
    topics.*.subscribers.*.delete
    This event triggers when a subscriber to a topic is deleted. Returns Topic Object
    messages.*
    This event triggers on any message event. Returns Message Object
    messages.*.create
    This event triggers when a message is created. Returns Message Object
    messages.*.delete
    This event triggers when a message is deleted. Returns Message Object
    messages.*.update
    This event triggers when a message is updated. Returns Message Object

The * wildcard matches any resource ID. You can use specific IDs instead of wildcards to subscribe only to events from a particular table, bucket, or function.

For example, to trigger only when rows are created in a specific table:

databases.<DATABASE_ID>.tables.<TABLE_ID>.rows.*.create

Keep your subscriptions specific. Subscribing to * (all events) on a busy project will result in a high volume of requests to your endpoint.

What the webhook payload looks like

The webhook body is JSON. The payload mirrors the API response for the event type. For a row create event, you get the full row object. For a user create event, you get the user object.

Example payload for a users.*.create event:

JSON
{
  "$id": "user_abc123",
  "$createdAt": "2026-03-26T10:00:00.000+00:00",
  "name": "Jane Smith",
  "email": "jane@example.com",
  "status": true,
  "emailVerification": false,
  "labels": []
}

Appwrite also sends several headers with every webhook request:

HeaderDescription
X-Appwrite-Webhook-Id
The webhook's ID in your project
X-Appwrite-Webhook-Events
Comma-separated list of matching events
X-Appwrite-Webhook-Name
The name you gave the webhook
X-Appwrite-Webhook-User-Id
ID of the user who triggered the event (if any)
X-Appwrite-Webhook-Project-Id
Your Appwrite project ID
X-Appwrite-Webhook-Signature
HMAC-SHA1 signature for verification
User-Agent
Always Appwrite-Server

Verifying webhook signatures

Anyone who knows your endpoint URL could send fake webhook requests. Appwrite signs every webhook payload with HMAC-SHA1 using a secret key, and you should verify this signature on every request.

The signature is computed as:

HMAC-SHA1(webhookUrl + rawBody, signingKey)

Where webhookUrl is the full URL of your endpoint (including protocol and path), rawBody is the raw request body string, and signingKey is the signing key shown in the webhook's configuration in the Appwrite Console.

Here's how to verify in Node.js:

JavaScript
const crypto = require('crypto');

function verifyWebhookSignature(req, signingKey) {
  const receivedSignature = req.headers['x-appwrite-webhook-signature'];
  const webhookUrl = 'https://yourapp.com/webhooks/appwrite'; // must match exactly
  const rawBody = req.rawBody; // ensure you have the raw body, not parsed JSON

  const expectedSignature = crypto
    .createHmac('sha1', signingKey)
    .update(webhookUrl + rawBody)
    .digest('base64');

  return receivedSignature === expectedSignature;
}

app.post('/webhooks/appwrite', express.raw({ type: 'application/json' }), (req, res) => {
  const rawBody = req.body.toString('utf8');

  if (!verifyWebhookSignature({ headers: req.headers, rawBody }, process.env.WEBHOOK_SIGNING_KEY)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const payload = JSON.parse(rawBody);
  const events = req.headers['x-appwrite-webhook-events'];

  // handle the event
  handleWebhookEvent(events, payload);

  res.status(200).json({ received: true });
});

Two things to watch for:

  • Use the raw body before JSON parsing. Once parsed, the byte-for-byte representation may differ.
  • The URL must match exactly, including any trailing slash.

Always return a 200 response quickly. Appwrite will retry failed deliveries, so if your handler takes too long or returns a non-2xx status, you'll receive duplicate events. Acknowledge receipt immediately and process asynchronously if needed.

Customer identity without the hassle

Add secure authentication in minutes, not weeks.

  • checkmark icon Built-in security and compliance
  • checkmark icon Multiple login methods
  • checkmark icon Custom authentication flows
  • checkmark icon Multi-factor authentication

Real use cases

CDN cache invalidation: Subscribe to storage.buckets.*.files.*.update and purge the CDN cache for the affected file URL when an asset is updated.

Slack notifications: Subscribe to users.*.create and post a message to a Slack channel whenever a new user signs up. Useful for tracking growth in early-stage apps.

JavaScript
async function handleWebhookEvent(events, payload) {
  if (events.includes('users') && events.includes('create')) {
    await fetch('https://hooks.slack.com/services/...', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        text: `New user: ${payload.name} (${payload.email})`
      })
    });
  }
}

Data sync to external systems: Subscribe to row create, update, and delete events and mirror changes to an external analytics database, a search index like Meilisearch or Algolia, or a data warehouse.

Automated emails: Subscribe to users.*.sessions.*.create and send a "new sign-in" security notification via your email provider when a session is created from a new location.

Audit logging: Subscribe broadly across databases and storage events and write every event to an append-only audit log table with the user ID from X-Appwrite-Webhook-User-Id.

Debugging webhooks

If your endpoint isn't receiving requests, check:

  1. The webhook is enabled in the Appwrite Console (there's an active/inactive toggle).
  2. Your endpoint URL is publicly reachable. Localhost won't work unless you're using a tunnel like ngrok or Cloudflare Tunnel.
  3. The events you subscribed to are actually firing. Use the Appwrite Console to manually trigger an action and confirm the event matches your subscription.
  4. Your server returns a 2xx response. Non-2xx responses are treated as failures.

For local development, tools like ngrok or Cloudflare Tunnel give your local server a public HTTPS URL you can paste directly into the webhook configuration.

Add webhooks to your Appwrite project

Webhooks connect Appwrite events to any external system without polling. Configure them in the Console, verify signatures to ensure authenticity, and return fast responses to handle retries cleanly.

Start building with Appwrite today

Get started