DRAFT — Preliminary version, do not share. · Version préliminaire, ne pas partager.

Cloud functions

Cloud functions run your own code inside Fundamentum, on an HTTP call or on every message of a topic, without servers to manage. This page shows you how to write a function, deploy it with the fun CLI, trigger it, and read its execution history.

Cloud functions: an HTTP call, a message on a topic or an action triggers your function in an isolated sandbox; its output goes to the HTTP response or to project topics, and every execution is recorded

What you can do with them

You write functions in Go, Rust, JavaScript or Python. Each execution runs in an isolated sandbox, and every execution is recorded with its logs and errors.

How a function runs

A function is a program that reads one JSON document on standard input and writes its result on standard output:

{
  "input": "<base64 of the request body or topic message>",
  "context": {"function_id": "<function-id>", "project_id": 1234},
  "metadata": {"<key>": "<base64 value>"}
}
Trigger Input Where the output goes
HTTP: a call to the Public API The request body, as is The API response
Topic: a message on an input topic The message value The output topic, if you set one

A topic-triggered function can run more than once for the same message; make it idempotent. By default a function processes one execution at a time and queues the others; set scaling.pool_size (greater than 1) to run several in parallel.

The runtime, build targets and SDK are described in Runtime and SDK.

Before you begin

1. Write the function

This Go function decodes a two-byte temperature frame and returns JSON. It uses only the standard library:

package main

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"
)

type request struct {
	Input    []byte            `json:"input"` // base64 in the JSON, decoded by encoding/json
	Metadata map[string][]byte `json:"metadata"`
}

func main() {
	var req request
	if err := json.NewDecoder(os.Stdin).Decode(&req); err != nil || len(req.Input) < 2 {
		fmt.Fprintln(os.Stderr, "invalid input")
		os.Exit(1)
	}
	tenths := int16(binary.BigEndian.Uint16(req.Input[:2]))
	json.NewEncoder(os.Stdout).Encode(map[string]float64{"temperature": float64(tenths) / 10})
}

Build it for the function runtime with the command given on the Runtime and SDK page.

2. Create the function

fun functions new temp-decoder --project <project-id> --language go \
  --description "Decode temperature frames" \
  --connector <input-topic-id>:<output-topic-id> \
  --variable UNIT=celsius

temp-decoder is a local name the CLI keeps for you, so later commands don't need the IDs. Leave out --connector for a function triggered by HTTP only. Use --ask to be prompted for missing values. Connectors that would form a cycle between topics are rejected.

3. Upload the code

fun functions upload temp-decoder <path-to-compiled-function>

Each upload replaces the previous code. Files can be up to 1 GiB.

4. Invoke it over HTTP

printf '\000\347' > frame.bin
fun functions invoke -n temp-decoder -i frame.bin

The raw request, with optional metadata headers:

POST https://api.fundamentum-iot.com/v2/projects/<project-id>/functions/<function-id>:invoke
Authorization: Bearer $TOKEN
X-Function-Device: <serial-number>

<request body>

The response gives the start time, the duration in seconds and the output. format is json when the output is valid JSON, unicode for other text, and base64 for binary output:

{
  "status": "success",
  "data": {
    "started_at": "Thu, 22 Oct 2026 14:30:00 UTC",
    "execution_time": 0.004,
    "output": {"format": "json", "value": {"temperature": 23.1}}
  }
}
Status Meaning
404 The function does not exist in this project
408 The execution reached its timeout
424 No code has been uploaded yet

5. Check the execution history

fun functions executions list -n temp-decoder

Each execution shows its source (http or pubsub), started_at, execution_time, log and error. Executions are kept for 7 days.

Manage functions

Task Command
List a project's functions fun functions list --project <project-id>
Edit the configuration (timeouts, variables, connectors, scaling) fun functions edit temp-decoder
Give an existing function a local name fun functions names add temp-decoder --project <project-id> --function <function-id>
Call the API directly fun api v2 functions <operation> --project-id <project-id>

What's next