Skip to main content

Functions

A function is server-side logic stored in ekoDB. It is parameterized, versioned and composable, and one function can combine queries, writes, full-text and vector search, key-value operations, AI calls and outbound HTTP requests in a single call. You define it once as JSON, and it runs next to your data.

One function, two callers

The same function is your app's API and your agents' tool:

  • Apps call it over the REST API or any client library.
  • Agents find it by name and run it as a tool.

Both callers run the same stored definition, and the same permission checks apply to both.

How it fits together​

Every caller reaches the same definition. Change the function and every caller gets the new behavior on its next call, with no app release and no agent prompt change.

Walkthrough: one function, an app and an agent​

This walkthrough uses an items collection shaped like the one in Build Your First AI Agent:

{ "name": "USB-C cable", "category": "cables", "quantity": 1, "restock_threshold": 5 }

Step 1: Define the function​

Creating, updating and deleting functions are admin operations, so use an admin key. The function below returns items whose quantity is below a threshold the caller passes in.

curl -X POST https://{EKODB_API_URL}/api/functions \
-H "Authorization: Bearer {ADMIN_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"label": "low_stock_items",
"name": "Low stock items",
"description": "Items whose quantity is below max_quantity",
"version": "1.0.0",
"parameters": {
"max_quantity": {
"required": false,
"default": 5,
"description": "Return items with a quantity below this number"
}
},
"functions": [
{
"type": "Query",
"collection": "items",
"filter": {
"type": "Condition",
"content": {
"field": "quantity",
"operator": "Lt",
"value": "{{max_quantity}}"
}
},
"limit": 50
}
],
"tags": ["inventory"]
}'

POST /api/functions creates a function and returns 409 Conflict if the label already exists. Update an existing one with PUT /api/functions/{id_or_label}. The description on the function and on each parameter is what an agent reads when it decides whether to use the function, so write it for that reader.

Step 2: Call it from your app​

Apps call a function with POST /api/functions/{label_or_id} and a JSON body of parameters. Exchange your key for a token first, and use that token wherever {TOKEN} appears below. Every client library wraps this as callFunction / call_function.

curl -X POST https://{EKODB_API_URL}/api/functions/low_stock_items \
-H "Authorization: Bearer {TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "max_quantity": 5 }'

A call returns { "records": [...], "stats": {...} }. Record values follow the same use_typed_values setting as find and query, so a client configured for typed values gets the same shape from a function as from a read. Omitted optional parameters take their defaults, a missing required parameter is rejected, and an unknown parameter name is rejected.

The function is now an endpoint for your app. Rust, Go and Kotlin call it the same way; see Client Libraries: Functions.

Step 3: Have an agent call the same function​

Agents do not need one tool per function. They use three built-in tools:

ToolWhat the agent does with it
list_functionsFinds the functions it can call, with their labels, names, descriptions and parameter names
get_functionReads one function's full definition, including its steps and parameters
call_functionRuns a function by label, with { "label": "...", "params": { ... } }

Open a chat session with tools turned on, scoped to the items collection and to the function tools, then ask a question the function answers:

# 1. Create a chat session with the function tools enabled
SESSION=$(curl -s -X POST https://{EKODB_API_URL}/api/chat \
-H "Authorization: Bearer {TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"collections": [{
"collection_name": "items",
"fields": [{"field_name": "name"}, {"field_name": "category"}]
}],
"llm_provider": "openai",
"llm_model": "gpt-4",
"system_prompt": "You manage inventory. Prefer stored functions over raw queries.",
"tool_config": {
"enabled": true,
"allowed_tools": ["list_functions", "get_function", "call_function"]
}
}' | jq -r '.chat_id')

# 2. Ask a question the function answers
curl -X POST https://{EKODB_API_URL}/api/chat/$SESSION/messages \
-H "Authorization: Bearer {TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "message": "Which items have fewer than 3 in stock?" }'

The agent calls list_functions, sees low_stock_items and its max_quantity parameter, and runs it:

{
"label": "low_stock_items",
"params": { "max_quantity": 3 }
}

It answers from the records the function returns, and the response lists each tool call in tool_call_history. An AI Agent deployment uses the same three tools, so an agent you deploy from the dashboard can find and run low_stock_items with no extra setup.

An agent whose key has admin privileges and whose session allows write operations can also create, update and delete functions and create schedules for them. A session's write setting alone does not bypass the admin-only checks on those operations. Whichever way a function was made, every caller runs that same definition.

Permissions​

The same rules apply whether an app or an agent makes the call.

  • Defining needs an admin key. Creating, updating and deleting functions, and creating schedules for them, are admin operations.
  • Calling needs a valid token. Any valid token for the instance can call any function, by id or label (POST /api/functions/{label_or_id}) or through a path route. Per-function call grants are on the roadmap.
  • A function's steps run with the server's own authority. The calling key's collection grants and field restrictions are not applied to the steps, so a function can read and write collections the key could not reach directly. Treat each function as a privileged operation: review it as one, and keep it to the single operation you want to expose.
  • An agent's call_function is limited by its session. A chat session runs a function the same way, and the session's collection scope and tool configuration decide what it may run: a function that reaches a collection outside that scope, through a nested stage or a called function, is refused.
  • Writes made by a function are not yet audited. The audit trail covers direct writes; a function's own writes add no entry yet. Running a function as its caller or its author, and auditing its writes under that identity, are on the roadmap.
Customer-facing agents

For an agent your own users talk to, give it stored functions instead of raw read and write tools. Each function is a reviewed, versioned operation with declared parameters, and the agent can do only what those functions allow.

Triggers​

Apps and agents are not the only callers. A function can also run on a timer, on an inbound event, or behind a URL of your choosing.

TriggerHow it calls the functionRuns as
ScheduleA cron schedule (POST /api/schedules, six-field cron with a timezone) runs the function with stored parameters. See Scheduled Functions.The schedule's recorded author
WebhookExternal services such as Stripe or GitHub POST signed events to /api/webhook/{name}. ekoDB verifies the HMAC-SHA256 signature, then calls the receiver's function with the JSON body as parameters. A missing or wrong signature returns 401.The receiver's recorded author
Custom routeGive a function an http_method and an http_path such as /users/:id, and it answers at /api/route/users/{id} with path placeholders passed as parameters. These routes use the same authentication as POST /api/functions/{label}.The authenticated caller, as above

A webhook receiver names the function to call, the shared secret and the signature header (X-Hub-Signature-256 by default). Agents manage receivers with the webhook_receiver tool.

What a function can do​

A function is an ordered list of steps whose results flow from one to the next. The step types cover:

  • Reads and search: Query, FindById, FindOne, TextSearch, VectorSearch, HybridSearch
  • Writes: Insert, BatchInsert, Update, UpdateById, Upsert, Delete and more, optionally as one transaction
  • Shaping: Group, AddFields, Project, Count
  • Control flow: If, ForEach, Parallel, TryCatch, Return, Validate, and CallFunction to compose functions
  • Key-value and caching: KV reads and writes, and stale-while-revalidate caching
  • AI: Chat completions and Embed for embeddings
  • Auth and crypto: password hashing, JWT sign and verify, HMAC, AES-GCM and TOTP
  • Outbound HTTP: call any REST API from inside the function

The full catalog, parameter rules, result chaining and transaction semantics are in Functions Architecture.

Next steps​