Infra & wire reference

The concrete REST endpoints and NATS subjects inflow-fusion speaks. Useful if you're implementing the infra side, debugging traffic, or writing a backend in another language.

The concrete REST endpoints and NATS subjects inflow-fusion speaks. Useful if you're implementing the infra side, debugging traffic, or writing a backend in another language.

Authentication

Every REST call from the SDK to infra carries:

Authorization: Bearer <JWT>

The JWT is minted locally (jwt.SigningMethodHS256, claim {"admin": true}) and signed with INFLOW_INFRA_JWT_SECRET — infra and your backend must share this secret out of band. There is no login flow; possession of the secret is the credential. The same helper (makeTokenWithHs256) is reused to authenticate against individual engine instances when they have their own jwt_secret configured in their Portal.

REST: your backend → infra

MethodPathCalled byPurpose
GET/account/inflow/credinflow.InitBackendgetCredFetch the NATS credential (models.Cred) for the inflow account
GET/inflow/resource?per_page={n}inflow.InflowWire.ReloadResourcesList registered engine instances (models.RegisteredInflow)
GET/account/id/{accountId}spaces.fetchAccount (via GetAccountById/GetAccountCred)Fetch an Account (seed, pub key, policy) by id, used to mint scoped plugin credentials

Response envelopes are {"data": ..., "error": ...}; the SDK unwraps .Data and treats a non-null .Error or a non-2xx status as failure.

REST: your backend → engine instance

MethodPathCalled byPurpose
POST{engineUrl}/engineProcess.ExecStart a process: body is models.ProcessRequest
POST{engineUrl}/ps/stop/{pid}Process.Stop / inflow.StopProcessStop a running process

engineUrl comes from the round-robin pool (inflow.GetResourceCandid); if it has no scheme it's prefixed with http://, and if it has no port it's suffixed with models.INFLOW_REST_PORT (9001).

ProcessRequest

type ProcessRequest struct {
    Context      ContextTopicsPattern // NATS subjects the engine should use for this run's context
    Flow         FlowEngine           // NATS subject to fetch the flow definition
    PID          string               // process id, auto-generated (UUID) if empty
    StartNodeId  string
    Settings     Settings             // timeouts, node execution cap
    Meta         map[string]string    // free-form; also used to fill subject templates
}

type Settings struct {
    RequestTimeOut   int64  // per NATS request, seconds (default 5)
    ExecuteTimeOut   int64  // whole process, seconds (default 3600)
    ProcessNodeLimit uint16 // safety cap on nodes visited (default 500)
}

Context.Getter/Context.Setter/Flow.GetFlow are subject templates auto-filled from contextId/flowId/any Meta entries unless you set them explicitly (see nodes.md and inflow.NewProcess).

ProcessResponse

type ProcessResponse struct {
    Data struct {
        PID string
    }
    Error any
}

NATS: engine ↔ your backend

Your backend subscribes to three subjects on init (inflow.InflowWire.connectAndListen). The {param} placeholders are NATS wildcard subjects (*) when subscribing, and get filled with real values when the engine publishes a request.

Subject templateDirectionHandlerPurpose
inflow.req.flow.get.{flowId}engine → backendIInflowService.RetrieveFlowReturn the compiled models.Flow for this id
inflow.req.context.get.{contextId}engine → backendIInflowService.RetrieveContextReturn the current models.ContextDoc
inflow.req.context.set.{contextId}engine → backendIInflowService.UpdateContextPersist an updated models.ContextDoc

These defaults live in svcHandler.DefaultGetFlowSvc / DefaultGetContextSvc / DefaultSetContextSvc and can be overridden by constructing your own svcHandler.SvcTopic patterns.

ContextDoc

type ContextDoc struct {
    Data   string         `json:"data"`   // opaque to the SDK — typically JSON-encoded per-node scope data
    Header map[string]any `json:"header"`
}

NATS: your backend's own extrinsic services

You register arbitrary subjects with svcHandler.ImplHandlerOnSubject(name, topic, handler). Internally this subscribes on topic.ConvertToSubscribe() (all {param} placeholders replaced with *), and before invoking your handler it sets a recv_subject header to the exact subject the message arrived on — this is how a wildcard subject like my.internal.svc.persist.* lets one handler serve many logical topics (e.g. .persist.orders vs .persist.tasks):

svcHandler.ImplHandlerOnSubject("db_handler", svcHandler.SvcTopic("my.internal.svc.persist.*"),
    func(header nats.Header, data []byte) ([]byte, error) {
        table := strings.Split(header.Get("recv_subject"), ".")[4]
        // ...
        return []byte(`{"status":"saved"}`), nil
    })

Handlers registered this way are also tracked in a process-local registry (svcHandler.GetSvc / GetAllSvcs), keyed by the name argument — useful if a compiler needs to resolve a logical service name back to its subject pattern (see compilers/vueflow.md).