Skip to main content

/qefro protocol

Protocol version documented here: 1 (protocol_version: "1").

SDK constants: SDK_NAME = '@qefro-ai/backend', SDK_VERSION = '1.7.0' (as of the inspected package).

Transport

  • Method / path: POST to endpointPath (default /qefro)
  • Body: JSON ProtocolRequest
  • Auth: HMAC headers — authentication.md
  • Response headers set by SDK: X-Qefro-Protocol, X-Qefro-Protocol-Version, X-Qefro-SDK, X-Qefro-Version

Request types

type QefroRequestType =
| 'ping'
| 'tools.list'
| 'capabilities.list'
| 'tool.invoke'
| 'tool.resume';

Common fields

FieldTypeNotes
protocol_versionstringMust be "1"
request_idstringCorrelation
typeQefroRequestTypeDispatch key
organization_idstring?Tenant/org
conversation_idstring?Conversation
channelstring?e.g. whatsapp, widget
identityobject?Channel identity attributes
toolstring?Required for invoke/resume
parametersobject?Tool input
authenticationobject?Prior auth context
resume_tokenstring?Challenge resume
challenge_responsestring?OTP / challenge answer
personobject | null?Customer Hub Person snapshot
platformobject?Storage / customer / marketing / organization / channels bindings

Responses

typeShape (summary)
pong{ protocol_version?, sdk_version? }
tools.list{ tools: RegisteredTool[], protocol_version?, sdk_version? }legacy; prefer capabilities.list
capabilities.list{ tools, flows, events?, webhooks?, schedules?, marketing?, organization?, protocol_version?, sdk_version?, sdk_name? }
result{ output, authentication_context?, person_mutations? }
challenge{ resume_token, challenge }
error{ code, message }

Dispatch

  1. Verify signature + optional protocol header
  2. Parse body
  3. Switch on type
  4. For tool.invoke / tool.resume, build ToolContext and run the handler
  5. Return JSON

Implementation detail: Flows, events, webhooks, and schedules are advertised on capabilities.list only. The JS SDK process does not execute app.flow / app.event / app.webhook / app.schedule handlers — the Qefro Runtime owns delivery and FlowRunner.

Implementation detail: app.listenhandleHttp does not pass request headers into handle(), so x-qefro-trace-idctx.trace_id works when using handleRaw(body, headers) today. Prefer logging request_id from the body for correlation on the default listen path.

There is no dedicated GET /health route in the SDK. Health = signed pingpong (Org Portal Test Connection).

HTTP status codes used by SDK listen:

StatusWhen
200Protocol response body
400Protocol header mismatch
401Invalidinvalid_signature`
404Wrong method/path
500Uncaught handler error → internal_error

Error codes (protocol body)

CodeMeaning
invalid_signatureHMAC failed (also HTTP 401)
protocol_mismatchUnsupported version
invalid_requestMissing tool / resume fields
not_foundUnknown tool or resume token
deniedAuth denied
customer_not_foundCustomer auth failed
person_not_foundPerson required but missing
configuration_errorMisconfiguration surfaced by handler path
internal_errorUnexpected failure

Platform egress paths

CallerHow /qefro is reached
ACS SdkWebhookClientDirect POST to webhook_url, or via connector-manager POST /v1/invoke with target_id: sdk:{connection_id} + endpoint + signing_secret
Runtime / managed installconnector-manager install:{solution} → installation binding endpoint
connector-managerSigns v1= and POSTs {endpoint}/qefro

Implementation detail: Until ACS connection registry is synced into connector-manager, sdk:{id} targets require endpoint (and optionally signing_secret) on the invoke request. ACS already passes both. Registry sync so CM can resolve sdk: without endpoint is not implemented.