Back to Changelog

Feb 6, 2026

Latest updates and announcements

Markdown

Webhook Subscriptions API & Connection Expiry Events

A new API for managing webhook configurations with event filtering, HMAC signature verification, and support for platform lifecycle events. This replaces the legacy project-level webhook settings with a more flexible, subscription-based model.

Summary

ChangeTypeAction Required
New Webhook Subscriptions APINew FeatureNo
composio.connected_account.expired eventNew FeatureOpt-in
Legacy webhook endpointsDeprecatedMigration recommended
webhook_url, webhook_secret in ProjectDeprecatedUse new API

API Overview

See the API Reference for complete details.

Endpoints

MethodEndpointDescription
POST/api/v3/webhook_subscriptionsCreate a subscription
GET/api/v3/webhook_subscriptionsList all subscriptions
GET/api/v3/webhook_subscriptions/{id}Get subscription details
PATCH/api/v3/webhook_subscriptions/{id}Update subscription
DELETE/api/v3/webhook_subscriptions/{id}Delete subscription
POST/api/v3/webhook_subscriptions/{id}/rotate_secretRotate signing secret
GET/api/v3/webhook_subscriptions/event_typesList available event types

Key Capabilities

  • Event filtering: Subscribe only to events you need
  • HMAC-SHA256 signatures: Every webhook includes a cryptographic signature for verification
  • Secret rotation: Rotate signing secrets on demand

Creating a Subscription

curl -X POST "https://backend.composio.dev/api/v3/webhook_subscriptions" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-server.com/webhooks/composio",
    "enabled_events": ["composio.trigger.message"],
    "version": "V3"
  }'

Response:

{
  "id": "ws_your-subscription-id",
  "webhook_url": "https://your-server.com/webhooks/composio",
  "version": "V3",
  "enabled_events": ["composio.trigger.message"],
  "secret": "<your-webhook-secret>",
  "created_at": "2026-02-06T12:00:00.000Z",
  "updated_at": "2026-02-06T12:00:00.000Z"
}

The secret is only returned once at creation time or when rotated. Store it securely for signature verification.

Notes

  • 1 subscription per project: Currently limited to one webhook subscription per project. This will be expanded in future releases.
  • HTTPS required: Webhook URLs must use HTTPS in production environments.

New Event: composio.connected_account.expired

A new platform event that notifies you when an OAuth2 connected account's authentication expires and cannot be automatically refreshed.

This event is only available in V3 format. We strongly recommend using V3 for all new integrations to access the latest features and follow standard webhook practices.

Use Cases

  • Prompt users to re-authenticate before workflows fail
  • Track connection health across your user base
  • Automate re-connection flows
  • Build proactive notification systems

Subscribing to Connection Expiry Events

curl -X POST "https://backend.composio.dev/api/v3/webhook_subscriptions" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-server.com/webhooks/composio",
    "enabled_events": [
      "composio.trigger.message",
      "composio.connected_account.expired"
    ],
    "version": "V3"
  }'

Payload Structure

The composio.connected_account.expired event follows the V3 envelope format:

{
  "id": "evt_847cdfcd-d219-4f18-a6dd-91acd42ca94a",
  "timestamp": "2026-02-06T12:00:00.000Z",
  "type": "composio.connected_account.expired",
  "metadata": {
    "project_id": "pr_your-project-id",
    "org_id": "ok_your-org-id"
  },
  "data": {
    "toolkit": {
      "slug": "gmail"
    },
    "auth_config": {
      "id": "ac_your-auth-config-id",
      "auth_scheme": "OAUTH2",
      "is_composio_managed": true,
      "is_disabled": false
    },
    "id": "ca_your-connected-account-id",
    "status": "EXPIRED",
    "created_at": "2025-12-01T10:00:00.000Z",
    "updated_at": "2026-02-06T12:00:00.000Z",
    "status_reason": "OAuth refresh token expired",
    "is_disabled": false
  }
}

The data object matches the response from GET /api/v3/connected_accounts/{id}, making it easy to process with existing code and SDK types.


Verifying Webhook Signatures

All webhooks include an HMAC signature in the webhook-signature header. Use the SDK's built-in verification functions or see the Triggers documentation for implementation details.


Available Event Types

Query available events and their version compatibility:

curl "https://backend.composio.dev/api/v3/webhook_subscriptions/event_types" \
  -H "x-api-key: YOUR_API_KEY"
Event TypeDescriptionSupported Versions
composio.trigger.messageTrigger events from integrationsV1, V2, V3
composio.connected_account.expiredConnection authentication expiredV3 only

Deprecations

Deprecated Endpoints

The following legacy endpoints are deprecated and will be removed in a future release:

Deprecated EndpointReplacement
GET /api/v3/org/project/webhookGET /api/v3/webhook_subscriptions
POST /api/v3/org/project/webhook/updatePOST /api/v3/webhook_subscriptions
DELETE /api/v3/org/project/webhookDELETE /api/v3/webhook_subscriptions/{id}
POST /api/v3/org/project/webhook/refreshPOST /api/v3/webhook_subscriptions/{id}/rotate_secret

Deprecated Fields in Project Response

FieldStatusNotes
webhook_urlDeprecatedUse Webhook Subscriptions API
webhook_secretDeprecatedUse Webhook Subscriptions API
event_webhook_urlDeprecatedNever implemented
is_new_webhookDeprecatedUse Webhook Subscriptions API

Backward Compatibility

No immediate action required. Your existing webhook configurations will continue to work.

What We've Done For You

  • Automatic migration: We've created a webhook subscription for all existing projects that had webhook URLs configured, with composio.trigger.message enabled by default
  • Same payload format: If you were using V1, V2, or V3 triggers, they continue with the same format

What Continues to Work

  • Legacy webhook endpoints (deprecated but functional)
  • Existing project webhook configurations
  • All existing trigger payload formats (V1, V2, V3)
  • Signature verification with your existing secret

Payload Version Comparison

VersionFormatRecommendation
V1Legacy flat structureFor backward compatibility only
V2Nested with metadataFor existing integrations
V3Structured envelope with id, timestamp, type, metadata, dataRecommended for all new integrations

75+ More Toolkits Get Typed Responses & Consistent Response Schema Wrapping

We've expanded typed response coverage to 75+ additional toolkits. In total, over 130 toolkits now return strongly typed response objects. Additionally, we've standardized response schema wrapping so that all action responses consistently nest their output under a top-level data field.

Breaking Change for latest Version

Two breaking changes ship in this release:

  1. Newly typed toolkits — If your code depends on the old response_data structure for any of the 75+ newly typed toolkits listed below, you'll need to update your code to work with the new typed response schemas.

  2. Consistent response wrapping — Actions that previously had data at the root level of their response schema now wrap the entire response under a data field. See the migration guide below.

Consistent Response Schema Wrapping

Previously, actions whose response schema already contained a data field at the root level would surface all fields (including data) alongside successful and error at the top level. Now, all action responses are uniformly wrapped: the full response object is nested inside a data field, with successful and error at the top level.

Affected: Toolkits with data in their response model (e.g., Pipedrive PIPEDRIVE_LIST_UPDATES_ABOUT_A_DEAL)

These actions had a data field in their original response schema. Previously, those fields were spread at the root level alongside successful and error. Now, they are nested under a top-level data field.

Before:

{
  "data": { "deal_id": 1, "field_key": "stage_id", "old_value": "1", "new_value": "2" },
  "successful": true,
  "error": null
}

After:

{
  "data": {
    "data": { "deal_id": 1, "field_key": "stage_id", "old_value": "1", "new_value": "2" }
  },
  "successful": true,
  "error": null
}

If your code accesses fields directly at the root level (e.g., result["data"]), update it to access them under result["data"]["data"] instead.

Not affected: Toolkits without data in their response model (e.g., GitHub GITHUB_GET_THE_LATEST_RELEASE)

These actions never had a data field in their original response schema, so their wrapping behavior is unchanged. The response fields are nested under data as before.

{
  "data": {
    "url": "https://api.github.com/repos/octocat/Hello-World/releases/1",
    "tag_name": "v1.0.0",
    "name": "v1.0.0",
    "draft": false,
    "prerelease": false,
    "author": { "login": "octocat", "id": 1 }
  },
  "successful": true,
  "error": null
}

No migration needed for these toolkits.

75+ Newly Typed Response Toolkits

All outputs for these toolkits now return strongly typed objects with clear field documentation instead of generic response_data blobs. Combined with the 60+ toolkits typed in the previous release, over 130 toolkits now have typed responses.