Skip to content
ArtificialFlow

SDKs

Three clients ship with release v1.1.0. Node.js can run a whole integration. Python and Go are for workers that pick up service tasks. Anything else uses the HTTP API.

All three send Authorization: Bearer and expect a machine identity with only the artificialflow client role. Workers also send X-Workflow-Worker-Protocol-Version: v1. The gateway address is http://localhost:9100/api on a local stack.

ClientUse it when
Node.jsYou want workflows, instances, inbox calls, messages, and workers from one package.
PythonA Python service should activate jobs, do the work, and complete or fail them.
GoThe worker already lives in Go, next to the product module.

Node.js

Install @artificialflow/nodejs-sdk at version 1.1.0, the same line as the platform. It needs Node.js 20 or newer. baseUrl defaults to http://localhost:9100/api, and query calls go to ${baseUrl}/query. Pass either auth or token, not both.

npm install @artificialflow/nodejs-sdk

For a long-running app, let the SDK fetch and refresh a client-credentials token from your OIDC provider. The application should have only artificialflow client, and the token should include the backend audience, normally workflow-backend.

import { ArtificialFlowClient } from "@artificialflow/nodejs-sdk"

const client = new ArtificialFlowClient({
  baseUrl: "https://app.example.com/api",
  auth: {
    type: "oauth-client-credentials",
    profile: {
      type: "oauth-client-credentials",
      tokenUrl: process.env.OIDC_TOKEN_URL,
      clientId: process.env.ARTIFICIALFLOW_CLIENT_ID,
      clientSecret: process.env.ARTIFICIALFLOW_CLIENT_SECRET,
    },
  },
})

const workflows = await client.listWorkflows({ page: 1, pageSize: 100 })
const instance = await client.startInstance("order-process", { orderId: "123" })
await client.publishMessage("MsgOrderPlaced", "123", { amount: 100 })
await client.publishSignal("OrderApproved", { orderId: "123" })
await client.publishEscalation("NEED_HELP", { reason: "timeout" })

That provider call sends the client id and secret in the form body and expects access_token plus expires_in. If your provider wants HTTP Basic, or an audience or resource parameter, keep using its own OAuth library and hand the SDK a callback. The callback returns the raw token, without a Bearer prefix.

const client = new ArtificialFlowClient({
  baseUrl: "https://app.example.com/api",
  token: () => getProviderAccessToken(),
})

A fixed token is fine for a short smoke test. Do not leave one in a worker that runs for days unless something else replaces it before it expires. client.setToken switches that client over to the token you pass and stops the automatic refresh.

cd clients/nodejs-sdk
npm ci
npm test
ARTIFICIALFLOW_TOKEN="$EXTERNAL_IAM_ACCESS_TOKEN" \
  ARTIFICIALFLOW_BASE_URL=http://localhost:9100/api \
  node examples/sdk-smoke-test.js

The smoke test checks the signed-in principal and lists workflows. Optional environment variables start a process, publish a message, or activate one job: ARTIFICIALFLOW_WORKFLOW_KEY, ARTIFICIALFLOW_BUSINESS_KEY, ARTIFICIALFLOW_MESSAGE_NAME, ARTIFICIALFLOW_MESSAGE_CORRELATION_KEY, and ARTIFICIALFLOW_WORKER_JOB_TYPE.

What the client can do

It is a thin wrapper over the same gateway the HTTP guide describes.

  • Deploy, list, search, fetch, and delete workflow definitions.
  • Start instances, search them, read one, update variables, complete a task, or delete an instance.
  • List an inbox, open an item, list user tasks, claim, complete, and read completed work.
  • Publish a message, a signal, or an escalation.
  • Activate jobs, complete them, fail them, extend a lock, and read worker capabilities.
  • Read engine metrics, the current principal, and identity configuration.

Identity administration methods are on the client too. On an external IAM deployment, people and machine credentials are still created in your provider. See the HTTP API for which identity routes that deployment actually serves.

A worker

createWorker polls /jobs/activate and completes or fails each job. Stop it on shutdown so the engine can hand the lock to someone else.

const worker = client.createWorker("payment-service", async (job) => {
  return { paymentStatus: "success" }
}, {
  workerName: "payment-worker",
  autoStart: true,
})

process.on("SIGINT", () => worker.stop())

An inbox for people

Keep the machine credential on your backend. Sign the person in with your own login, then pass that person on each inbox call so ArtificialFlow can filter by assignee and candidate group. Do not send the SDK token to a browser. An identity that also holds artificialflow admin is rejected by the inbox.

const actingUser = {
  subject: signedInUser.subject,
  username: signedInUser.username,
  email: signedInUser.email,
  name: signedInUser.name,
  roles: signedInUser.roles,
}

const inbox = await client.listInboxItems({ actingUser })
const current = await client.getInboxInstance(inbox[0].id, { actingUser, includeCompleted: true })
const tasks = await client.listUserTasks(current.id, { actingUser })
await client.claimUserTask(current.id, tasks[0].executionId, { actingUser })
await client.completeUserTask(current.id, tasks[0].executionId, { actingUser })

Python

clients/python-sdk is a worker, not a second workflow client. The package name in that directory is artificialflow-worker version 0.1.0. It needs Python 3.10 or newer. Install it from a checkout of v1.1.0. It is not published as its own registry package in this release.

pip install -e clients/python-sdk

Worker.run loops on POST /jobs/activate. The handler returns variables for /jobs/{key}/complete. If the handler raises, the client fails the job and lowers the remaining retries. Each request gets its own Idempotency-Key.

from artificialflow_worker import Worker

def handle(job):
    return {"ok": True, "elementId": job.get("elementId")}

Worker(
    base_url="http://localhost:9100/api",
    token="...",
    job_type="golden-validate",
    worker_name="python-sample",
    handler=handle,
).run()

Replace the token with one from your provider. The same role and audience rules apply. The loop is the right shape for a service task. Starting processes and reading the inbox stay on the Node.js client or the HTTP API.

Go

Go workers use backend/libs/worker inside the product module. NewClient wants the gateway URL and a bearer token. From there the calls match the HTTP worker routes: activate, complete, fail, extend the lock, and read capabilities. The protocol version constant is v1.

import "github.com/artificialflow/artificialflow/backend/libs/worker"

client, err := worker.NewClient(worker.ClientConfig{
    BaseURL:     "http://localhost:9100/api",
    BearerToken: os.Getenv("ARTIFICIALFLOW_TOKEN"),
})
if err != nil {
    return err
}
jobs, err := client.ActivateJobs(ctx, worker.ActivateJobsRequest{
    Type:           "payment-service",
    Worker:         "payment-worker",
    MaxJobs:        1,
    TimeoutMs:      5000,
    LockDurationMs: 30000,
})

The import path is github.com/artificialflow/artificialflow/backend/libs/worker. Use it from a program in that module. The header and route details are on the Workers page, and make worker-conformance checks the wire format.

Look after the credentials

  • One machine identity per application. Keep it on artificialflow client only.
  • Store client secrets in a secret manager, not in the repo or in logs.
  • 401 means the token is missing, expired, or aimed at the wrong issuer or audience.
  • 403 means the token is valid and the role is not allowed to do that.
  • Stop workers on shutdown so a locked job can be picked up again.