Skip to main content

SDK application development

The Qefro SDK connects external systems to Qefro over /qefro. It is not how you build a Marketplace App.

Marketplace Apps are metadata executed by Qefro Runtime — start at Build your first app and Runtime vs SDK.

Use this page for Focus ERP, Yaaz, ABM, on-prem POS, or any customer system of record.

Package​

npm install @qefro-ai/backend

Import:

import { Qefro } from '@qefro-ai/backend';
// or: import Qefro from '@qefro-ai/backend';

Application shape​

Application
├── Tools app.tool
├── Flows app.flow (metadata; runtime executes)
├── Events app.event / webhook / schedule
├── Customer app.customer(provider) optional
├── Marketing app.marketing({…}) metadata
├── Organization app.organization({…}) metadata
└── HTTP app.listen → POST /qefro

Constructor​

new Qefro({
signingSecret: string;
protocolVersion?: string; // default '1'
maxTimestampSkewSeconds?: number; // default 300
endpointPath?: string; // default '/qefro'
});

Middleware​

app.use(async (ctx, next) => { await next(); });
app.before(async (ctx) => {});
app.after(async (ctx, result) => {});

Tool registration signatures​

All supported by app.tool:

app.tool('name', handler);
app.tool('name', metadata, handler);
app.tool('name', handler, metadata);
app.tool({ name: 'name', …metadata }, handler);

See tools.md.

Flows​

Flows are metadata only. The SDK advertises them on capabilities.list; the Qefro Runtime orchestrates execution.

app.flow({
id: 'reservation',
version: 1,
trigger: { type: 'conversation' }, // or event / schedule / webhook
})
.ask({ /* … */ })
.tool({ /* … */ })
.complete({ /* … */ });

Events, webhooks, schedules​

app.event({ name: 'shopify.order.created', description: '…' }, async (ctx) => {});
app.webhook({ name: 'shipment.delivered' }, async (ctx) => {});
app.schedule({ name: 'daily.digest', cron: '0 9 * * *' }, async (ctx) => {});

Advertised under capabilities.list as events, webhooks, schedules.

Implementation detail: These handlers are stored and advertised only. The SDK /qefro dispatcher does not call them — the Qefro Runtime owns delivery.

Marketing & organization​

Call once each:

app.marketing({ version: 1, audiences: […], variables: […], actions: […], landingPages: […], channels: […] });
app.organization({ version: 1, events: […], actions: […], tasks: […] });

Organization capability ids must be opaque (no . / app prefix).

Listen​

const handle = await app.listen({ port: 8080, host: '0.0.0.0', path: '/qefro' });
// handle.url → http://0.0.0.0:8080/qefro
// await handle.close();

For embedding in an existing HTTP framework, use handleRaw(body, headers) (verifies signature then dispatches).

Shared code across models​

Keep tools, schemas, and domain logic identical whether the adapter is an org SDK Connection or a packaged hosting: external process. Marketplace Apps are metadata and do not use this SDK.