@OnEndpoint
Expose custom HTTP endpoints for webhooks, APIs, and integrations.
Overview
The @OnEndpoint decorator exposes methods as HTTP endpoints on your agent's Cloud Run service. Use it for webhooks, custom APIs, health checks, and integration points.
Basic Usage
import { HyperfoldAgent, OnEndpoint } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'custom-agent', type: 'custom' })
export class CustomAgent {
@OnEndpoint('/health')
async healthCheck() {
return {
status: 'healthy',
timestamp: new Date().toISOString(),
version: '1.2.0',
};
}
@OnEndpoint('/metrics')
async getMetrics() {
const stats = await this.analytics.getCurrentStats();
return {
active_sessions: stats.sessions,
requests_per_minute: stats.rpm,
avg_response_time: stats.avgLatency,
};
}
@OnEndpoint('/webhook/shopify')
async handleShopifyWebhook(request: Request) {
const event = request.body;
await this.processShopifyEvent(event);
return { received: true };
}
}
Endpoints are accessible at https://<agent-url>/<path>. The agent URL is shown after deployment.
HTTP Methods
Support different HTTP methods for RESTful APIs:
import { OnEndpoint, HttpMethod } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'api-agent', type: 'custom' })
export class ApiAgent {
@OnEndpoint('/products')
async listProducts() {
return await this.catalog.list();
}
@OnEndpoint('/products', { method: 'POST' })
async createProduct(request: Request) {
const data = request.body;
return await this.catalog.create(data);
}
@OnEndpoint('/products/:id', { method: 'PUT' })
async updateProduct(request: Request) {
const { id } = request.params;
const data = request.body;
return await this.catalog.update(id, data);
}
@OnEndpoint('/products/:id', { method: 'DELETE' })
async deleteProduct(request: Request) {
const { id } = request.params;
await this.catalog.delete(id);
return { deleted: true };
}
@OnEndpoint('/orders/:id', { methods: ['GET', 'PATCH'] })
async handleOrder(request: Request) {
const { id } = request.params;
if (request.method === 'GET') {
return await this.orders.get(id);
} else {
return await this.orders.update(id, request.body);
}
}
}
Request Handling
Access request data including headers, body, and query parameters:
@HyperfoldAgent({ name: 'webhook-handler', type: 'custom' })
export class WebhookHandler {
@OnEndpoint('/webhook/stripe')
async handleStripeWebhook(request: Request) {
const signature = request.headers['stripe-signature'];
const isValid = await this.stripe.verifySignature(
request.rawBody,
signature
);
if (!isValid) {
return {
status: 401,
body: { error: 'Invalid signature' },
};
}
const event = request.body;
switch (event.type) {
case 'payment_intent.succeeded':
await this.handlePaymentSuccess(event.data);
break;
case 'payment_intent.failed':
await this.handlePaymentFailure(event.data);
break;
}
return { received: true };
}
@OnEndpoint('/api/search')
async searchEndpoint(request: Request) {
const query = request.query.q;
const limit = parseInt(request.query.limit) || 10;
const page = parseInt(request.query.page) || 1;
const results = await this.catalog.search(query, { limit, page });
return {
status: 200,
headers: {
'X-Total-Count': results.total.toString(),
'X-Page': page.toString(),
},
body: results.items,
};
}
@OnEndpoint('/upload', { method: 'POST' })
async handleUpload(request: Request) {
const files = request.files;
const fields = request.body;
for (const file of files) {
await this.storage.upload(file.buffer, file.originalName);
}
return { uploaded: files.length };
}
}
Request Object
| Property | Type | Description |
|---|---|---|
method | string | HTTP method (GET, POST, etc.) |
headers | object | Request headers |
body | any | Parsed request body |
rawBody | Buffer | Raw body for signature verification |
query | object | Query string parameters |
params | object | URL path parameters |
files | File[] | Uploaded files (multipart) |
Authentication
Secure endpoints with various authentication methods:
import { OnEndpoint, Auth } from '@hyperfold/actions-sdk';
@HyperfoldAgent({ name: 'secure-agent', type: 'custom' })
export class SecureAgent {
@OnEndpoint('/public/health')
async publicHealth() {
return { status: 'ok' };
}
@OnEndpoint('/api/data', { auth: 'api_key' })
async protectedData(request: Request) {
console.log(`Request from: ${request.auth.keyId}`);
return { data: 'protected' };
}
@OnEndpoint('/api/user', { auth: 'jwt' })
async getUserData(request: Request) {
const userId = request.auth.sub;
return await this.users.get(userId);
}
@OnEndpoint('/webhook/partner', { auth: 'custom' })
async partnerWebhook(request: Request) {
const apiKey = request.headers['x-partner-key'];
const isValid = await this.validatePartnerKey(apiKey);
if (!isValid) {
return { status: 403, body: { error: 'Invalid partner key' } };
}
return await this.processPartnerEvent(request.body);
}
@OnEndpoint('/admin/stats', { auth: 'jwt', roles: ['admin'] })
async adminStats(request: Request) {
return await this.analytics.getAdminStats();
}
}
// Configure auth in agent decorator
@HyperfoldAgent({
name: 'secure-agent',
type: 'custom',
auth: {
apiKey: {
header: 'X-API-Key',
validate: async (key) => {
return await db.apiKeys.exists(key);
},
},
jwt: {
issuer: 'https://auth.example.com',
audience: 'hyperfold-agent',
},
},
})
export class SecureAgentWithConfig { }
Always authenticate webhook endpoints to prevent unauthorized access. Use signature verification for payment and order webhooks.
Explore built-in tools in Tools Reference.