> ## Documentation Index
> Fetch the complete documentation index at: https://docs.magmadeploy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Add HTTP endpoints to your Magma agents

## Overview

Hooks in Magma allow you to expose HTTP endpoints that external services can call to interact with your agent. They're perfect for handling webhooks, callbacks, and API integrations.

## Implementation

To add a hook to your agent, use the `@hook` decorator:

```typescript theme={null}
import { MagmaAgent } from "@pompeii-labs/magma";
import { hook } from "@pompeii-labs/magma/decorators";
import { Request, Response } from 'express';

class MyAgent extends MagmaAgent {
    @hook('myHookName')
    async handleWebhook(req: Request, res: Response) {
        const data = req.body;
        res.status(200).json({ status: "success", received: data });
    }
}
```

The first parameter of the decorator is the name of the hook.
The second parameter is optional, and is covered in the [Advanced Usage](#advanced-usage) section.

The function being decorated should take in an express Request and Response, which you can access directly to read and write data.

***

## Hook URLs

When your agent is deployed, hooks are automatically exposed at:

```
https://api.magmadeploy.com/v1/agents/<AGENT_ID>/hooks/<HOOK_NAME>
```

## Request Handling

Hooks support both GET and POST methods by default. The request and response objects are the standard Express Request and Response type, giving you access to:

* `req.query` - URL query parameters
* `req.body` - POST request body
* `req.headers` - HTTP headers
* `req.params` - URL parameters

You can also use the `res` object to send a response to the caller.

* `res.status(code).json(body)` - Send a JSON response
* `res.send(body)` - Send a string or buffer response
* `res.end()` - End the response

For more information on the Express Request and Response objects, see the [Express documentation](https://expressjs.com/en/api.html#req).

## Common Use Cases

### OAuth Callbacks

```typescript theme={null}
class MyAgent extends MagmaAgent {
    @hook('oauth-callback')
    async handleOAuth(req: Request, res: Response) {
        const { code } = req.query;
        const tokens = await this.exchangeCodeForTokens(code as string);
        res.status(200).json({ success: true, tokens });
    }
}
```

***

### Webhook Listeners

```typescript theme={null}
class MyAgent extends MagmaAgent {
    @hook('stripe-webhook')
    async handleStripeEvent(req: Request, res: Response) {
        const event = req.body;
        switch (event.type) {
            case 'payment.succeeded':
                await this.processPayment(event.data);
                break;
            case 'subscription.created':
                await this.activateSubscription(event.data);
                break;
        }

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

***

### API Endpoints

```typescript theme={null}
class MyAgent extends MagmaAgent {
    @hook('status')
    async getStatus(req: Request, res: Response) {
        const metrics = await this.getSystemMetrics();
        res.status(200).json({
            status: "healthy",
            uptime: process.uptime(),
            metrics
        });
    }
}
```

***

## Best Practices

1. **Validation**: Always validate incoming data

```typescript theme={null}
@hook('user-update')
async updateUser(req: Request) {
    const { userId, data } = req.body;
    if (!userId || !data) {
        throw new Error('Missing required fields');
    }
    await this.updateUserData(userId, data);
}
```

2. **Error Handling**: Implement proper error handling

```typescript theme={null}
@hook('process-data')
async processData(req: Request, res: Response) {
    try {
        const result = await this.processPayload(req.body);
        res.status(200).json({ success: true, result });
    } catch (error) {
        res.status(500).json({
            success: false,
            error: error.message
        });
    }
}
```

3. **Security**: Implement authentication when needed

```typescript theme={null}
@hook('secure-endpoint')
async secureEndpoint(req: Request, res: Response) {
    const apiKey = req.headers['x-api-key'];
    if (!apiKey || !this.validateApiKey(apiKey)) {
        res.status(401).json({ error: 'Unauthorized' });
    }
    const data = await this.getSecureData();
    res.status(200).json({ success: true, data });
}
```

<Warning>
  Hooks are publicly accessible endpoints. Always implement appropriate security measures for sensitive operations.
</Warning>

***

## Advanced Usage

### Static Hooks

If you don't need a hook to access any agent state, you can define it as a static hook.

```typescript theme={null}
@hook('myStaticHook')
static async doSomething(req: Request, res: Response) {
    res.status(200).json({ success: true });
}
```

### Session Routing for Hooks

If you are unfamiliar with sessions, you should first review the concept of [Sessions](/magma-framework/sessions).

You can direct the hook to a specific session id using the session argument of the second parameter of the decorator. This argument is an optionally async function that takes in the request, and returns the session id.

```typescript theme={null}
@hook('user-update', { session: async (req: Request) => req.body.userId })
async updateUser(req: Request, res: Response) {
    const { userId, data } = req.body;

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

This will direct the hook to the session with the id that matches the `userId` in the request body.
To learn more about sessions, see the [Sessions](/magma-framework/sessions) page.

## Limitations

* File uploads are limited to 10MB
* Webhook timeout is 30 seconds
* Rate limiting applies based on your plan

<Tip>
  For long-running operations, consider using a job instead of a hook, or implement an async pattern with a status endpoint.
</Tip>
