@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
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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:
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import { OnEndpoint, HttpMethod } from '@hyperfold/actions-sdk'; @HyperfoldAgent({ name: 'api-agent', type: 'custom' })export class ApiAgent { // Default is GET @OnEndpoint('/products') async listProducts() { return await this.catalog.list(); } // Explicit POST @OnEndpoint('/products', { method: 'POST' }) async createProduct(request: Request) { const data = request.body; return await this.catalog.create(data); } // PUT for updates @OnEndpoint('/products/:id', { method: 'PUT' }) async updateProduct(request: Request) { const { id } = request.params; const data = request.body; return await this.catalog.update(id, data); } // DELETE @OnEndpoint('/products/:id', { method: 'DELETE' }) async deleteProduct(request: Request) { const { id } = request.params; await this.catalog.delete(id); return { deleted: true }; } // Multiple methods @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:
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@HyperfoldAgent({ name: 'webhook-handler', type: 'custom' })export class WebhookHandler { @OnEndpoint('/webhook/stripe') async handleStripeWebhook(request: Request) { // Access headers const signature = request.headers['stripe-signature']; // Verify webhook signature const isValid = await this.stripe.verifySignature( request.rawBody, signature ); if (!isValid) { return { status: 401, body: { error: 'Invalid signature' }, }; } // Parse body (automatically parsed for JSON) const event = request.body; // Handle different event types 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) { // Access query parameters 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 with custom status and headers 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) { // Handle multipart form data 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:
typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import { OnEndpoint, Auth } from '@hyperfold/actions-sdk'; @HyperfoldAgent({ name: 'secure-agent', type: 'custom' })export class SecureAgent { // Public endpoint (no auth) @OnEndpoint('/public/health') async publicHealth() { return { status: 'ok' }; } // API key authentication @OnEndpoint('/api/data', { auth: 'api_key' }) async protectedData(request: Request) { // API key validated automatically // Access key info via request.auth console.log(`Request from: ${request.auth.keyId}`); return { data: 'protected' }; } // JWT authentication @OnEndpoint('/api/user', { auth: 'jwt' }) async getUserData(request: Request) { // JWT validated and decoded const userId = request.auth.sub; return await this.users.get(userId); } // Custom authentication @OnEndpoint('/webhook/partner', { auth: 'custom' }) async partnerWebhook(request: Request) { // Implement custom auth logic 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); } // Role-based access @OnEndpoint('/admin/stats', { auth: 'jwt', roles: ['admin'] }) async adminStats(request: Request) { // Only accessible by users with admin role 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) => { // Custom validation logic 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.