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>/endpoint/<function-endpoint>

Example:

https://eu.restapi.com/my-api/endpoint/calculate-shipping

Configuration

Basic Settings

SettingDescription
NameUnique identifier for the function
DescriptionOptional documentation
EnabledToggle to enable/disable
EndpointURL path (e.g., calculate-shipping)

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

PropertyDescription
bodyRequest body (JSON)
methodHTTP method (GET, POST, PUT, DELETE)
headersRequest headers (filtered for security)
queryQuery parameters
userAuthenticated user information (if any)

Returning Responses

Return data from your function:

// Return JSON data
return {
success: true,
result: calculatedValue
};

The returned object becomes the HTTP response body.

Use Cases

Custom Calculations

Perform calculations that require server-side logic:

// Calculate shipping cost
const { weight, destination, method } = body;

let baseCost = weight * 0.5;

if (destination === 'international') {
baseCost *= 2.5;
}

if (method === 'express') {
baseCost *= 1.5;
}

return {
shippingCost: Math.round(baseCost * 100) / 100,
estimatedDays: method === 'express' ? 2 : 7
};

Webhook Handlers

Receive webhooks from external services:

// Handle Stripe webhook
const event = body;

switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;

// Update order status
await fetch(`${apiUrl}/orders/${paymentIntent.metadata.orderId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
paymentStatus: 'paid',
stripePaymentId: paymentIntent.id
})
});
break;

case 'payment_intent.payment_failed':
// Handle failure
break;
}

return { received: true };

Aggregation Endpoints

Create endpoints that aggregate data:

// Dashboard statistics
const [orders, customers, products] = await Promise.all([
fetch(`${apiUrl}/orders?count=true`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()),
fetch(`${apiUrl}/customers?count=true`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json()),
fetch(`${apiUrl}/products?count=true`, { headers: { 'Authorization': `Bearer ${token}` } }).then(r => r.json())
]);

return {
totalOrders: orders.meta.count,
totalCustomers: customers.meta.count,
totalProducts: products.meta.count,
recentOrders: orders.items.slice(0, 5)
};

Multi-Step Operations

Orchestrate complex operations:

// Create order with inventory check
const { customerId, items } = body;

// Check inventory
for (const item of items) {
const product = await fetch(`${apiUrl}/products/${item.productId}`, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());

if (product.stockLevel < item.quantity) {
return {
error: `Insufficient stock for ${product.name}`,
available: product.stockLevel
};
}
}

// Create order
const order = await fetch(`${apiUrl}/orders`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
customerId,
items,
status: 'pending',
total: items.reduce((sum, i) => sum + i.price * i.quantity, 0)
})
}).then(r => r.json());

// Reserve inventory
for (const item of items) {
await fetch(`${apiUrl}/products/${item.productId}`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
stockLevel: { $decrement: item.quantity }
})
});
}

return { orderId: order.id, status: 'created' };

Authentication Extensions

Implement custom authentication flows:

// Verify external token and create session
const { externalToken } = body;

// Verify with external auth provider
const verification = await fetch('https://auth.example.com/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token: externalToken })
}).then(r => r.json());

if (!verification.valid) {
return { error: 'Invalid token' };
}

// Find or create user
let user = await fetch(`${apiUrl}/users?filter=externalId eq "${verification.userId}"`, {
headers: { 'Authorization': `Bearer ${token}` }
}).then(r => r.json());

if (user.items.length === 0) {
user = await fetch(`${apiUrl}/users`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
externalId: verification.userId,
email: verification.email,
name: verification.name
})
}).then(r => r.json());
}

return {
userId: user.id || user.items[0].id,
authenticated: true
};

Calling Invocable Functions

From JavaScript

const response = await fetch('https://eu.restapi.com/my-api/endpoint/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/endpoint/calculate-shipping \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"weight": 2.5, "destination": "domestic", "method": "standard"}'

Best Practices

  • Use meaningful endpoint names/calculate-shipping is better than /func1
  • Validate input — Check request body and query parameters
  • Return consistent responses — Use a standard response structure
  • Handle errors gracefully — Return meaningful error messages
  • Set appropriate access control — Don't expose sensitive operations publicly
  • Document your endpoints — Use the description field