diff --git a/docs/docs.json b/docs/docs.json
index f0d3df154a..3ddd80a15d 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -45,7 +45,8 @@
"features/custom-instructions",
"features/direct-import",
"features/async-client",
- "features/memory-export"
+ "features/memory-export",
+ "features/webhook"
]
}
]
diff --git a/docs/features/webhook.mdx b/docs/features/webhook.mdx
new file mode 100644
index 0000000000..6adac8c599
--- /dev/null
+++ b/docs/features/webhook.mdx
@@ -0,0 +1,223 @@
+---
+title: Webhooks
+description: 'Configure and manage webhooks to receive real-time notifications about memory events'
+icon: "webhook"
+iconType: "solid"
+---
+
+## Overview
+
+Webhooks allow you to receive real-time notifications when memory events occur in your Mem0 project. Webhooks are configured at the project level, meaning each webhook is associated with a specific project and will only receive events from that project. You can configure webhooks to send HTTP POST requests to your specified URLs whenever memories are created, updated, or deleted.
+
+## Managing Webhooks
+
+### Get Webhooks
+
+Retrieve all webhooks configured for your project. By default, it uses the project_id from your client configuration, but you can optionally specify a different project:
+
+
+
+```python Python
+from mem0 import MemoryClient
+
+client = MemoryClient(api_key="your-api-key")
+
+# Get webhooks for the default project
+webhooks = client.get_webhooks()
+
+# Or specify a different project
+webhooks = client.get_webhooks(project_id="proj_123")
+print(webhooks)
+```
+
+```javascript JavaScript
+const { MemoryClient } = require('mem0ai');
+const client = new MemoryClient('your-api-key');
+
+// Get webhooks for the default project
+const webhooks = await client.getWebhooks();
+
+// Or specify a different project
+const webhooks = await client.getWebhooks("proj_123");
+console.log(webhooks);
+```
+
+```json Output
+[
+ {
+ 'id': 6,
+ 'url': 'https://mem0.ai',
+ 'name': 'mem0',
+ 'owner': 'john',
+ 'project': 'default-project',
+ 'secret': '3254dde069fe2490216dba7ca4e0f3595619a28e5909ba80d45caed7577f1040',
+ 'is_active': True,
+ 'created_at': '2025-02-18T22:59:56.804993-08:00',
+ 'updated_at': '2025-02-18T23:06:41.479361-08:00'
+ }
+]
+
+```
+
+
+
+### Create Webhook
+
+Create a new webhook for your project. The webhook will only receive events from the specified project:
+
+
+
+```python Python
+# Create a webhook in the default project
+webhook = client.create_webhook(
+ url="https://your-app.com/webhook",
+ name="Memory Logger"
+)
+
+# Or create in a specific project
+webhook = client.create_webhook(
+ url="https://your-app.com/webhook",
+ name="Memory Logger",
+ project_id="proj_123"
+)
+print(webhook)
+```
+
+```javascript JavaScript
+// Create a webhook in the default project
+const webhook = await client.createWebhook({
+ url: "https://your-app.com/webhook",
+ name: "Memory Logger"
+});
+
+// Or create in a specific project
+const webhook = await client.createWebhook({
+ url: "https://your-app.com/webhook",
+ name: "Memory Logger",
+ projectId: "proj_123"
+});
+console.log(webhook);
+```
+
+```json Output
+{
+ 'id': 1,
+ 'name': 'Memory Logger',
+ 'url': 'https://your-app.com/webhook',
+ 'project': 'default-project',
+ 'secret': '3254dde069fe2490216dba7ca4e0f3595619a28e5909ba80d45caed7577f1040',
+ 'is_active': True,
+ 'created_at': '2025-02-18T22:59:56.804993-08:00',
+ 'updated_at': '2025-02-18T23:06:41.479361-08:00'
+}
+```
+
+
+
+### Update Webhook
+
+Modify an existing webhook's configuration. Remember that webhooks can only be updated within their associated project:
+
+
+
+```python Python
+# Update webhook in default project
+updated_webhook = client.update_webhook(
+ webhook_id=1,
+ name="Updated Logger",
+ url="https://your-app.com/new-webhook"
+)
+
+# Or update in a specific project
+updated_webhook = client.update_webhook(
+ webhook_id=1,
+ name="Updated Logger",
+ url="https://your-app.com/new-webhook",
+ project_id="proj_123"
+)
+print(updated_webhook)
+```
+
+```javascript JavaScript
+// Update webhook in default project
+const updatedWebhook = await client.updateWebhook(1, {
+ name: "Updated Logger",
+ url: "https://your-app.com/new-webhook"
+});
+
+// Or update in a specific project
+const updatedWebhook = await client.updateWebhook(1, {
+ name: "Updated Logger",
+ url: "https://your-app.com/new-webhook",
+ projectId: "proj_123"
+});
+console.log(updatedWebhook);
+```
+
+```json Output
+{
+ "message": "Webhook updated successfully"
+}
+```
+
+
+
+### Delete Webhook
+
+Remove a webhook configuration from a project:
+
+
+
+```python Python
+# Delete webhook from default project
+response = client.delete_webhook(webhook_id=1)
+
+# Or delete from a specific project
+response = client.delete_webhook(webhook_id=1, project_id="proj_123")
+print(response)
+```
+
+```javascript JavaScript
+// Delete webhook from default project
+const response = await client.deleteWebhook(1);
+
+// Or delete from a specific project
+const response = await client.deleteWebhook(1, "proj_123");
+console.log(response);
+```
+
+```json Output
+{
+ "message": "Webhook deleted successfully"
+}
+```
+
+
+
+## Webhook Payload
+
+When a memory event occurs in your project, Mem0 sends a POST request to your webhook URL with the following payload structure:
+
+```json
+{
+ "id": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5",
+ "data": {
+ "memory": "Name is Alex"
+ },
+ "event": "ADD"
+}
+```
+
+## Best Practices
+
+1. **Implement Retry Logic**: Your webhook endpoint should be able to handle temporary failures and implement appropriate retry mechanisms.
+
+2. **Verify Webhook Source**: Implement security measures to verify that webhook requests are coming from Mem0.
+
+3. **Process Events Asynchronously**: Handle webhook events asynchronously to prevent timeouts and ensure reliable processing.
+
+4. **Monitor Webhook Health**: Regularly check your webhook logs to ensure proper functionality and handle any delivery failures.
+
+If you have any questions, please feel free to reach out to us using one of the following methods:
+
+
\ No newline at end of file
diff --git a/mem0/client/main.py b/mem0/client/main.py
index 154db809f1..312e58e281 100644
--- a/mem0/client/main.py
+++ b/mem0/client/main.py
@@ -524,6 +524,112 @@ def chat(self):
"""
raise NotImplementedError("Chat is not implemented yet")
+ @api_error_handler
+ def get_webhooks(self, project_id: Optional[str] = None) -> Dict[str, Any]:
+ """Get webhooks configuration for the project.
+
+ Args:
+ project_id: The ID of the project to get webhooks for.
+
+ Returns:
+ Dictionary containing webhook details.
+
+ Raises:
+ APIError: If the API request fails.
+ ValueError: If project_id is not set.
+ """
+
+ project_id = project_id or self.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to access webhooks")
+
+ response = self.client.get(f"api/v1/webhooks/{project_id}/webhook/")
+ response.raise_for_status()
+ capture_client_event("client.get_webhook", self)
+ return response.json()
+
+ @api_error_handler
+ def create_webhook(self, url: str, name: str, project_id: Optional[str] = None) -> Dict[str, Any]:
+ """Create a webhook for the current project.
+
+ Args:
+ url: The URL to send the webhook to.
+ name: The name of the webhook.
+
+ Returns:
+ Dictionary containing the created webhook details.
+
+ Raises:
+ APIError: If the API request fails.
+ ValueError: If project_id is not set.
+ """
+ project_id = project_id or self.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to create webhook")
+
+ payload = {"url": url, "name": name}
+ response = self.client.post(f"api/v1/webhooks/{project_id}/webhook/", json=payload)
+ response.raise_for_status()
+ capture_client_event("client.create_webhook", self)
+ return response.json()
+
+ @api_error_handler
+ def update_webhook(
+ self, webhook_id: int, name: Optional[str] = None, url: Optional[str] = None, project_id: Optional[str] = None
+ ) -> Dict[str, Any]:
+ """Update a webhook configuration.
+
+ Args:
+ webhook_id: ID of the webhook to update
+ name: Optional new name for the webhook
+ url: Optional new URL for the webhook
+ project_id: The ID of the project to update the webhook for.
+
+ Returns:
+ Dictionary containing the updated webhook details.
+
+ Raises:
+ APIError: If the API request fails.
+ ValueError: If project_id is not set.
+ """
+ project_id = project_id or self.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to update webhook")
+
+ payload = {k: v for k, v in {"name": name, "url": url}.items() if v is not None}
+ response = self.client.put(f"api/v1/webhooks/{project_id}/webhook/{webhook_id}/", json=payload)
+ response.raise_for_status()
+ capture_client_event("client.update_webhook", self, {"webhook_id": webhook_id})
+ return response.json()
+
+ @api_error_handler
+ def delete_webhook(self, webhook_id: int, project_id: Optional[str] = None) -> Dict[str, str]:
+ """Delete a webhook configuration.
+
+ Args:
+ webhook_id: ID of the webhook to delete
+ project_id: The ID of the project to delete the webhook for.
+
+ Returns:
+ Dictionary containing success message.
+
+ Raises:
+ APIError: If the API request fails.
+ ValueError: If project_id is not set.
+ """
+ project_id = project_id or self.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to delete webhook")
+
+ response = self.client.delete(f"api/v1/webhooks/{project_id}/webhook/{webhook_id}/")
+ response.raise_for_status()
+ capture_client_event("client.delete_webhook", self, {"webhook_id": webhook_id})
+ return response.json()
+
def _prepare_payload(
self, messages: Union[str, List[Dict[str, str]], None], kwargs: Dict[str, Any]
) -> Dict[str, Any]:
@@ -867,3 +973,58 @@ async def update_project(
async def chat(self):
raise NotImplementedError("Chat is not implemented yet")
+
+ @api_error_handler
+ async def get_webhooks(self, project_id: Optional[str] = None) -> Dict[str, Any]:
+ project_id = project_id or self.sync_client.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to access webhooks")
+
+ response = await self.async_client.get(
+ f"api/v1/webhooks/{project_id}/webhook/",
+ )
+ response.raise_for_status()
+ capture_client_event("async_client.get_webhook", self.sync_client)
+ return response.json()
+
+ @api_error_handler
+ async def create_webhook(self, url: str, name: str, project_id: Optional[str] = None) -> Dict[str, Any]:
+ project_id = project_id or self.sync_client.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to create webhook")
+
+ response = await self.async_client.post(
+ f"api/v1/webhooks/{project_id}/webhook/", json={"url": url, "name": name}
+ )
+ response.raise_for_status()
+ capture_client_event("async_client.create_webhook", self.sync_client)
+ return response.json()
+
+ @api_error_handler
+ async def update_webhook(
+ self, webhook_id: int, name: Optional[str] = None, url: Optional[str] = None, project_id: Optional[str] = None
+ ) -> Dict[str, Any]:
+ project_id = project_id or self.sync_client.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to update webhook")
+
+ payload = {k: v for k, v in {"name": name, "url": url}.items() if v is not None}
+ response = await self.async_client.put(f"api/v1/webhooks/{project_id}/webhook/{webhook_id}/", json=payload)
+ response.raise_for_status()
+ capture_client_event("async_client.update_webhook", self.sync_client, {"webhook_id": webhook_id})
+ return response.json()
+
+ @api_error_handler
+ async def delete_webhook(self, webhook_id: int, project_id: Optional[str] = None) -> Dict[str, str]:
+ project_id = project_id or self.sync_client.project_id
+
+ if not project_id:
+ raise ValueError("project_id must be set to delete webhook")
+
+ response = await self.async_client.delete(f"api/v1/webhooks/{project_id}/webhook/{webhook_id}/")
+ response.raise_for_status()
+ capture_client_event("async_client.delete_webhook", self.sync_client, {"webhook_id": webhook_id})
+ return response.json()
diff --git a/pyproject.toml b/pyproject.toml
index db4bc9aa2b..a6e277b6ab 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mem0ai"
-version = "0.1.51"
+version = "0.1.52"
description = "Long-term memory for AI Agents"
authors = ["Mem0 "]
exclude = [