Invocable Functions
Invocable functions create custom HTTP endpoints that execute your code on demand. Use them for custom APIs, webhook handlers, and complex operations.
How It Works
- Define a unique endpoint path (e.g.,
calculate-shipping) - Configure which HTTP methods are allowed (GET, POST, PUT, DELETE)
- Set role-based access control per method
- Write JavaScript code to handle requests
- Call the endpoint via HTTP
URL Structure
https://<region>.restapi.com/<api-name>/_invoke/<function-name>
Example:
https://eu.restapi.com/my-api/_invoke/calculate-shipping
Configuration
Basic Settings
| Setting | Description |
|---|---|
| Name | Unique identifier for the function (used in URL) |
| Description | Optional documentation |
| Enabled | Toggle to enable/disable |
HTTP Methods
Configure which methods the endpoint accepts:
| Method | Typical Use |
|---|---|
GET | Retrieve data, calculations |
POST | Create resources, complex operations |
PUT | Replace resources |
DELETE | Remove resources |
Access Control
Unlike trigger and timer functions, invocable functions have role-based access control per HTTP method:
| Role | Description |
|---|---|
| Anonymous user | No authentication required |
| Authenticated user | Any logged-in user |
| Custom roles | Your defined roles |
Configure different permissions for each method. For example:
GET→ Anonymous (public)POST→ Authenticated users onlyDELETE→ Manager role only
Execution Context
What Your Code Receives
| Object | Description |
|---|---|
req.bodyJson | Parsed JSON request body |
req.body | Raw request body string |
req.method | HTTP method (GET, POST, PUT, DELETE) |
req.headers | Request headers (filtered for security) |
req.query | Query parameters |
me | Authenticated user information (if any) |
api | API information |
secrets | Configured secrets |
Returning Responses
Set the res object to return data:
// Return JSON response
res = {
status: 200,
bodyJson: {
success: true,
result: calculatedValue
}
};
// Or just set bodyJson (status defaults to 200)
res = {
bodyJson: { message: 'Done' }
};
Use Cases
Custom Calculations
Perform calculations that require server-side logic:
const { weight, destination, method } = req.bodyJson;
let baseCost = weight * 0.5;
if (destination === 'international') {
baseCost *= 2.5;
}
if (method === 'express') {
baseCost *= 1.5;
}
res = {
bodyJson: {
shippingCost: Math.round(baseCost * 100) / 100,
estimatedDays: method === 'express' ? 2 : 7
}
};
Webhook Handlers
Receive webhooks from external services:
// Handle Stripe webhook
const event = req.bodyJson;
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
// Update order status using built-in method
await patch(`orders/${paymentIntent.metadata.orderId}`, {
paymentStatus: 'paid',
stripePaymentId: paymentIntent.id
});
break;
case 'payment_intent.payment_failed':
// Handle failure
break;
}
res = { bodyJson: { received: true } };
Aggregation Endpoints
Create endpoints that aggregate data:
// Dashboard statistics - use built-in methods
const [ordersRes, customersRes, productsRes] = await Promise.all([
get('orders?count=true'),
get('customers?count=true'),
get('products?count=true')
]);
res = {
bodyJson: {
totalOrders: ordersRes.meta?.count || 0,
totalCustomers: customersRes.meta?.count || 0,
totalProducts: productsRes.meta?.count || 0,
recentOrders: ordersRes.data.slice(0, 5)
}
};
Multi-Step Operations
Orchestrate complex operations:
// Create order with inventory check
const { customerId, items } = req.bodyJson;
// Check inventory using built-in method
for (const item of items) {
const productRes = await get(`products/${item.productId}`);
const product = productRes.data[0];
if (product.stockLevel < item.quantity) {
res = {
status: 400,
bodyJson: {
error: `Insufficient stock for ${product.name}`,
available: product.stockLevel
}
};
return;
}
}
// Create order
const orderRes = await post('orders', {
customerId,
items,
status: 'pending',
total: items.reduce((sum, i) => sum + i.price * i.quantity, 0)
});
const orderId = orderRes.data[0];
// Reserve inventory
for (const item of items) {
const productRes = await get(`products/${item.productId}`);
const product = productRes.data[0];
await patch(`products/${item.productId}`, {
stockLevel: product.stockLevel - item.quantity
});
}
res = { bodyJson: { orderId, status: 'created' } };
Validation with Errors
Use validationErrors for user-facing validation:
const { email, name, age } = req.bodyJson;
if (!email) {
validationErrors.push('Email is required');
}
if (!name || name.length < 2) {
validationErrors.push('Name must be at least 2 characters');
}
if (age && age < 18) {
validationErrors.push('Must be 18 or older');
}
// If validationErrors has items, returns 400 automatically
if (validationErrors.length > 0) {
return; // Stop execution
}
// Proceed with valid data
const userRes = await post('users', { email, name, age });
res = { bodyJson: { userId: userRes.data[0], created: true } };
External API Integration
Call external APIs (requires paid tier):
// Verify address with external service
const { address } = req.bodyJson;
const verification = await fetch('https://api.addressvalidator.com/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${secrets.ADDRESS_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ address })
});
const result = await verification.json();
res = {
bodyJson: {
valid: result.valid,
standardized: result.standardizedAddress
}
};
Calling Invocable Functions
From JavaScript
const response = await fetch('https://eu.restapi.com/my-api/_invoke/calculate-shipping', {
method: 'POST',
headers: {
'Authorization': 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
weight: 2.5,
destination: 'domestic',
method: 'standard'
})
});
const result = await response.json();
console.log(result.shippingCost);
From cURL
curl -X POST https://eu.restapi.com/my-api/_invoke/calculate-shipping \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"weight": 2.5, "destination": "domestic", "method": "standard"}'
Best Practices
- Use meaningful function names —
calculate-shippingis better thanfunc1 - Validate input — Check
req.bodyJsonfields and usevalidationErrors - Use built-in methods —
get(),post(),patch()for internal API calls - Use
fetchonly for external APIs — External calls require paid tier - Set appropriate access control — Don't expose sensitive operations publicly
- Return consistent responses — Use a standard response structure