Skip to main content

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

  1. Define a unique endpoint path (e.g., calculate-shipping)
  2. Configure which HTTP methods are allowed (GET, POST, PUT, DELETE)
  3. Set role-based access control per method
  4. Write JavaScript code to handle requests
  5. 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

SettingDescription
NameUnique identifier for the function (used in URL)
DescriptionOptional documentation
EnabledToggle to enable/disable

HTTP Methods

Configure which methods the endpoint accepts:

MethodTypical Use
GETRetrieve data, calculations
POSTCreate resources, complex operations
PUTReplace resources
DELETERemove resources

Access Control

Unlike trigger and timer functions, invocable functions have role-based access control per HTTP method:

RoleDescription
Anonymous userNo authentication required
Authenticated userAny logged-in user
Custom rolesYour defined roles

Configure different permissions for each method. For example:

  • GET → Anonymous (public)
  • POST → Authenticated users only
  • DELETE → Manager role only

Execution Context

What Your Code Receives

ObjectDescription
req.bodyJsonParsed JSON request body
req.bodyRaw request body string
req.methodHTTP method (GET, POST, PUT, DELETE)
req.headersRequest headers (filtered for security)
req.queryQuery parameters
meAuthenticated user information (if any)
apiAPI information
secretsConfigured 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 namescalculate-shipping is better than func1
  • Validate input — Check req.bodyJson fields and use validationErrors
  • Use built-in methodsget(), post(), patch() for internal API calls
  • Use fetch only 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