Functions and flows
Make your Met call your own backend — a Function with an HTTP handler or a flow, linked to the Met.
An AI Function is ONE tool the Met can call (scopes functions:read / functions:write). When the Met decides to use it, it collects the arguments according to your parameters and fires the handler you defined. That is how you connect your own backend to the conversation.
Parameters: the tool's schema
Each FunctionParameter goes into the JSON schema the LLM sees. Only name is required:
const parameters = [
{ name: 'sku', description: 'Product code', required: true },
{ name: 'currency', description: 'Price currency', enum_values: ['COP', 'USD'] },
];
Available fields: name, description, required, type ('string' | 'number' | 'boolean'), enum_values (closed list; null/[] = free) and save_to (the contact's field_key where the collected value should persist, or null to not store it).
A Function without a handler is inert (not callable). You have two ways to give it one.
A) Direct HTTP handler
The shortest path to hitting your endpoint: pass http. The arguments the Met collects travel to your URL as a JSON body.
const fn = await met.functions.create({
name: 'check_price',
description: 'Looks up the current price of a SKU in our backend',
prompt: 'Use it when the customer asks about a product price.',
parameters,
http: {
url: 'https://api.your-company.com/prices',
method: 'POST',
auth_workspace_variable: 'api_token',
sign_secret_variable: 'price_signature',
timeout_ms: 15000,
},
});
Secrets do NOT go in the raw.
auth_workspace_variable(Bearer token, sent asAuthorization) andsign_secret_variable(signing secret) are referenced by workspace variable name. Create them first withmet.variables.set('api_token', 'sk_live_…', { encrypted: true })— see Workspace variables.
Meteor signs every call with X-Met-Signature (the same HMAC as the webhooks). Verify it in your endpoint without writing HMAC by hand:
const handle = met.tools.createHandler(process.env.PRICE_SIGNATURE);
app.post('/prices', (req, res) => {
let call;
try { call = handle(req.rawBody, req.headers['x-met-signature']); }
catch { return res.status(400).end(); }
res.json({ result: lookUpPrice(call.arguments) });
});
Static, NON-sensitive headers go in headers. timeout_ms is optional (default 30s, ceiling 60s).
B) Flow (flow_id)
When you need multi-step logic, branches or several nodes, point the Function at a Meteor Flow (scopes flows:write / automations:execute). The pattern is create → update with the canvas → publish:
const flow = await met.flows.create({ name: 'call-my-api' });
await met.flows.update(flow.id, {
draft_definition: {
nodes: [{ id: 'call', type: 'http.request', url: 'https://api.your-company.com/prices' }],
edges: [],
},
});
await met.flows.publish(flow.id); // the Met only invokes the published version
const fn = await met.functions.create({ name: 'check_price', parameters, flow_id: flow.id });
The http.request node can sign the request with X-Met-Signature just like the direct handler. Test the flow before publishing with met.flows.run(flow.id, { use_draft: true }).
Link it to the Met
Creating the Function does not activate it on any Met: it has to be linked.
await met.functions.link(agentId, fn.id); // idempotent
await met.functions.listForAgent(agentId); // → [12, 34] (linked ids)
await met.functions.unlink(agentId, fn.id); // unlink
To confirm your Function ended up available as a tool of a Met, use
met.agents.tools(agentId): it returns each tool with itssource('function'for yours) and whether it isdisabled. See Mets and their tools.
End-to-end
import Met from '@meteor.ia/sdk';
const met = new Met(process.env.MET_API_KEY, { workspaceId: 130 });
// 1. Secret by variable (not in the raw)
await met.variables.set('api_token', process.env.API_TOKEN, { encrypted: true });
// 2. Function with an HTTP handler
const fn = await met.functions.create({
name: 'check_price',
description: 'Looks up the current price of a SKU',
parameters: [{ name: 'sku', description: 'Product code', required: true }],
http: { url: 'https://api.your-company.com/prices', method: 'POST', auth_workspace_variable: 'api_token' },
});
// 3. Link it to the Met and try it with a run that uses it
await met.functions.link(agentId, fn.id);
const run = await met.runs.create({ met: 'Valeria', input: 'How much is SKU AB-12?' });
console.log(run.output); // the Met called your endpoint and answered with the price
See Run Mets (Runs) for the details of runs.create.