Skip to main content
Webhooks let your integration receive real-time updates from Hyperspell. Whenever a user connects a new account or a memory finishes indexing, Hyperspell will send a secure HTTP POST request to your webhook endpoint. To receive webhooks, navigate to the Dashboard and enter a webhook URL. You can choose which events to receive — connection notifications, indexing updates, or both. It is important that your webhook endpoint returns a 200 OK response to Hyperspell’s request.

Events

Hyperspell sends webhooks for the following events:
EventDescription
connection-createdA user has connected a new account (e.g. Notion, Google Drive, Slack)
index-startedA memory has started indexing
index-completedA memory has finished indexing

Webhook payload

You will receive a JSON payload with the following fields:
event
string
required
The event that triggered the webhook. One of connection-created, index-started, or index-completed.
app
string
required
The app slug that triggered the webhook.
user_id
string
The user id that triggered the webhook. Maybe be null.
source
string
required
The source that triggered the webhook, ie. notion, slack, web_crawler, etc.
resource_id
string
The resource id that triggered the webhook. Present on index-started and index-completed events. For the web_crawler source, this is the URL that started the crawl.
connection_id
string
The connection id. Present on connection-created events.
integration_id
string
The integration id. Present on connection-created events.
timestamp
int
The timestamp of the event in seconds since the Unix epoch.
Additionally, the following headers are included in the request:
X-Hyperspell-Signature
string
A SHA256 hash of the webhook payload using the app secret as the key. You can verify the hash to ensure the request is from Hyperspell.

Verifying the webhook

To verify that the webhook is coming from Hyperspell, you can use the X-Hyperspell-Signature header. This is a SHA256 hash of the webhook payload using the app’s secret as the key. You can get the secret from the Dashboard (it’s the same as the JWT Secret) You can verify the hash to ensure the request is from Hyperspell. Here’s an example of how to receive and verify the webhook:
from fastapi import FastAPI, Request
import hashlib
import hmac

def verify_webhook(payload, secret):
    hash = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
    return hmac.compare_digest(signagture, hash)

class WebhookPayload(pydantic.BaseModel):
    event: str
    app: str
    user_id: str | None
    source: str
    resource_id: str | None = None
    connection_id: str | None = None
    integration_id: str | None = None
    timestamp: int

app = FastAPI()

@router.post("/webhooks/hyperspell")
async def hyperspell_webhook(query: WebhookPayload, request: Request):
    # Verify that the request is from Hyperspell
    signature = request.headers.get("X-Hyperspell-Signature")
    if not verify_webhook(query, HYPERSPELL_JWT_SECRET):
        raise HTTPException(status_code=401, detail="Invalid signature")

    # Protect against replay attacks
    if query.timestamp < time.time() - 300:
        raise HTTPException(status_code=401, detail="Timestamp is too old")

    # Handle the webhook
    if query.event == "connection-created":
        # A user connected a new account
        ...
    elif query.event == "index-started":
        # A memory started indexing
        ...
    elif query.event == "index-completed":
        # A memory finished indexing
        ...

    return {"message": "Webhook received"}