Skip to main content

Qefro Python Backend SDK

qefro-backend is the Python framework for building Qefro Business Tool handlers and Business Flows. Register your tools and flows, serve the signed Qefro webhook, and let the Qefro Runtime orchestrate everything — including multi-step flows and customer verification.

Wire-compatible with the JavaScript and Rust SDKs: same signed protocol, same capabilities.list schema, same 8 flow step types.

Install

pip install qefro-backend

Zero runtime dependencies — it uses only the Python standard library.

Quick start

from qefro_backend import Qefro

app = Qefro(signing_secret="dev-secret")  # or QEFRO_SIGNING_SECRET from env

@app.tool("get_orders", auth="required", lookup={"required": ["email"]})
async def get_orders(ctx):
    customer = ctx.customer.require()
    return [{"orderId": "ord_1", "customerId": customer["id"]}]

app.run(8088)  # POST http://0.0.0.0:8088/qefro

Set the same signing secret in Admin Console → Business Tools → SDK Connections, then Sync Tools. Handlers may be sync or async.

Customer authorization

Register a provider to resolve and verify customers. auth="required" tools authorize automatically before the handler runs; a challenge outcome pauses the tool and asks the customer for a code, then resumes.

from qefro_backend import Qefro, CustomerProvider

app = Qefro("dev-secret")

class Customers(CustomerProvider):
    async def lookup(self, ctx):
        return {"id": ctx.identity.get("phone", "demo")}

    async def authorize(self, ctx):
        if not ctx.response:
            return ctx.auth.sms_otp(ctx.customer["id"], "Enter the code we texted you.")
        if ctx.response.strip() != "123456":
            return ctx.auth.sms_otp(ctx.customer["id"], "Wrong code, try again.")
        return ctx.auth.success(ctx.customer, {"type": "bearer_token", "access_token": "demo"})

app.customer(Customers())

Customer Hub (optional)

When QEFRO_CUSTOMER_HUB_ENABLED=true, tools can call Hub via platform.customer on tool.invoke (or QEFRO_CUSTOMER_HUB_URL + service token). Hub is optional — defaults keep existing apps working (ENABLED=false, OPTIONAL=true). Soft-skip returns None / no-ops when Hub is off or unreachable; set QEFRO_CUSTOMER_HUB_OPTIONAL=false to hard-fail.

@app.tool("create_reservation", auth="none")
async def create_reservation(ctx):
    customer = await ctx.customer.resolve({"whatsapp_number": ctx.identity.get("phone")})
    # Hub properties: ctx.customer.id, .phone_number, .whatsapp_number, .display_name
    await ctx.timeline.append({
        "event_type": "reservation.created",
        "payload": {"code": "R-1001"},
    })
    await ctx.membership.attach({"solution_id": "restaurant-pro"})
    await ctx.consent.grant({"purpose": "marketing"})
    return {"customer_id": customer["id"] if customer else None}

ctx.storage (when present in your stack) remains independent — Hub is never the sole path. External CRM auth via app.customer(provider) is unchanged.

Business Flows

Flows describe how your Business Tools are orchestrated. They are metadata only — the SDK advertises them through capabilities.list and the Qefro Runtime discovers, validates, versions, and executes them. Nothing runs inside the SDK.

(
    app.flow({
        "id": "order_lookup",              # immutable identity — renaming `name` never creates a new flow
        "name": "Order Lookup",
        "description": "Look up customer orders",
        "category": "crm",
        "tags": ["customer", "orders"],
        "intent": ["track order", "where is my order"],
        "inputs": ["email"],
        "outputs": ["get_orders"],
    })
    .ask("email", field="email", prompt="Please enter your email.")
    .tool("orders", tool_ref="get_orders")
    .complete("done", message="Here are your recent orders.")
)

Every step needs a unique id; tool steps reference an existing Business Tool by tool_ref. Step builders: .ask() .tool() .challenge() .upload() .condition() .delay() .approval() .complete(). A duplicate/empty flow or step id raises FlowError. See examples/order-approval for a full ask → tool → condition → approval → OTP-authenticated tool → complete flow.

Protocol

Message Purpose
ping Health / Test Connection
capabilities.list Discover tools and business flows for Sync Tools
tools.list Legacy tool-only discovery (still supported)
tool.invoke Run a handler
tool.resume Continue after a customer challenge reply

Requests are HMAC-SHA256 signed (X-Qefro-Signature / X-Qefro-Timestamp, payload v1:<timestamp>:<body>). Responses include X-Qefro-Protocol, X-Qefro-SDK, and X-Qefro-Version.

Examples

export QEFRO_SIGNING_SECRET=dev-secret
python examples/basic/server.py            # ask -> tool -> complete
python examples/order-approval/server.py   # condition + approval + OTP-authenticated tool

Docs

Development

pip install -e ".[dev]"
pytest

License

MIT

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

qefro_backend-1.1.0.tar.gz (19.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

qefro_backend-1.1.0-py3-none-any.whl (20.5 kB view details)

Uploaded Python 3

File details

Details for the file qefro_backend-1.1.0.tar.gz.

File metadata

  • Download URL: qefro_backend-1.1.0.tar.gz
  • Upload date:
  • Size: 19.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for qefro_backend-1.1.0.tar.gz
Algorithm Hash digest
SHA256 b46963a8fef0e5e1f0570fb90f118b03a8ed763bc8e86a93ba882c4efbbec70b
MD5 a89a1824c326700ffebd318b79a31da7
BLAKE2b-256 f48661b1c8a7745f0905e9dcdbfa70e0f61f4bed3d080ad78e29d824465770d1

See more details on using hashes here.

File details

Details for the file qefro_backend-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: qefro_backend-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for qefro_backend-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dc7d38f5d57bea42c02f1c8a4d25312eda351e9083a43da19d5f522715e1e9e7
MD5 d4735b7cc10a28abadcce823d0d3475a
BLAKE2b-256 34614d12ffff4edb693e93709bb7d8f9ce0e1354926453f666c924f63d07467c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page