Webhook Support (#2225)
This commit is contained in:
@@ -45,7 +45,8 @@
|
||||
"features/custom-instructions",
|
||||
"features/direct-import",
|
||||
"features/async-client",
|
||||
"features/memory-export"
|
||||
"features/memory-export",
|
||||
"features/webhook"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
223
docs/features/webhook.mdx
Normal file
223
docs/features/webhook.mdx
Normal file
@@ -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:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```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'
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Create Webhook
|
||||
|
||||
Create a new webhook for your project. The webhook will only receive events from the specified project:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```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'
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Update Webhook
|
||||
|
||||
Modify an existing webhook's configuration. Remember that webhooks can only be updated within their associated project:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```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"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
### Delete Webhook
|
||||
|
||||
Remove a webhook configuration from a project:
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```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"
|
||||
}
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## 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:
|
||||
|
||||
<Snippet file="get-help.mdx" />
|
||||
@@ -524,6 +524,112 @@ class MemoryClient:
|
||||
"""
|
||||
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 @@ class AsyncMemoryClient:
|
||||
|
||||
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()
|
||||
|
||||
@@ -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 <founders@mem0.ai>"]
|
||||
exclude = [
|
||||
|
||||
Reference in New Issue
Block a user