> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usefluency.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fluency Workflow Telemetry API

> Send completed automated workflow executions to Fluency so they can be analyzed beside human executions of the same process.

Send completed automated workflow executions to Fluency so they can be analyzed beside human executions of the same process.

The TypeScript and Python SDKs are the recommended integration because they create IDs, measure timings, preserve failures, retry delivery, and enforce payload limits. Use this HTTP API when your runtime cannot use either SDK or when you are building a custom adapter.

For SDK installation and integration examples, see [Fluency AI Agent SDKs](/fluency-ai-agent-sdks).

<Note>
  This is not meant to replace services like BrainTrust, LangTrace, and similar. This is taking telemetry from the business perspective, allowing you to optimize, manage, improve, and measure work against the broader business context.
</Note>

## Base URL

Fluency supplies the endpoint for your organization's home region during onboarding.

| Region        | Base URL                                   |
| ------------- | ------------------------------------------ |
| Australia     | `https://ap-southeast-2.wb.usefluency.com` |
| United States | `https://us-east-1.wb.usefluency.com`      |
| Singapore     | Supplied during onboarding                 |
| Hong Kong     | Supplied during onboarding                 |

Store this as `FLUENCY_WORKFLOW_ENDPOINT`. Do not copy a URL from another Fluency organization or choose a region based on latency; an organization's data remains in its assigned region.

<Warning>
  `FLUENCY_WORKFLOW_TELEMETRY_ENDPOINT` is an internal Fluency Server setting. Customer workflows use `FLUENCY_WORKFLOW_ENDPOINT`.
</Warning>

## Authentication

Send the organization-owned API key supplied by Fluency as a bearer credential:

```http theme={"system"}
Authorization: Bearer YOUR_FLUENCY_WORKFLOW_API_KEY
Content-Type: application/json
```

The key must:

* be owned by your Fluency organization;
* include the `workflow-telemetry:write` permission; and
* belong to an organization enabled for workflow telemetry.

The verified key determines the organization. Do not send an organization ID in the body, query string, or a custom header.

Store the key in your secret manager. Use separate keys for workflows or deployments that need independent audit history, rotation, or revocation. Never include the key in prompts, step input/output, artifacts, logs, or source control.

## Submit a run

```http theme={"system"}
POST /ext/workflow-telemetry/runs
```

The endpoint accepts one completed or failed workflow execution. Acceptance is durable, but process association and artifact reconciliation continue asynchronously.

### Minimal request

```bash theme={"system"}
curl --request POST \
  "$FLUENCY_WORKFLOW_ENDPOINT/ext/workflow-telemetry/runs" \
  --header "Authorization: Bearer $FLUENCY_WORKFLOW_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "run_id": "invoice-job-018f6f6e",
    "executor": {
      "type": "automation",
      "id": "accounts-payable-workflow",
      "name": "Accounts payable workflow",
      "version": "2026.09"
    },
    "name": "Process supplier invoice",
    "started_at": "2026-09-19T20:00:00Z",
    "ended_at": "2026-09-19T20:00:08Z",
    "status": "completed",
    "steps": [],
    "artifacts": [],
    "metadata": {}
  }'
```

### Complete request

```json theme={"system"}
{
  "run_id": "invoice-job-018f6f6e",
  "executor": {
    "type": "automation",
    "id": "accounts-payable-workflow",
    "name": "Accounts payable workflow",
    "version": "2026.09"
  },
  "name": "Process supplier invoice",
  "started_at": "2026-09-19T20:00:00Z",
  "ended_at": "2026-09-19T20:00:08Z",
  "status": "completed",
  "steps": [
    {
      "step_id": "read-invoice",
      "name": "Read invoice",
      "kind": "tool",
      "started_at": "2026-09-19T20:00:00Z",
      "ended_at": "2026-09-19T20:00:02Z",
      "status": "completed",
      "input": {
        "document_uri": "https://documents.example.com/invoices/INV-123"
      },
      "output": {
        "invoice_number": "INV-123",
        "total": 1250.0,
        "currency": "AUD"
      },
      "error": null
    },
    {
      "step_id": "approve-invoice",
      "name": "Approve invoice",
      "kind": "llm",
      "started_at": "2026-09-19T20:00:02Z",
      "ended_at": "2026-09-19T20:00:08Z",
      "status": "completed",
      "input": {
        "invoice_number": "INV-123"
      },
      "output": {
        "decision": "approved"
      },
      "error": null
    }
  ],
  "artifacts": [
    {
      "artifact_id": "invoice-job-018f6f6e-result",
      "name": "Invoice INV-123 approval",
      "kind": "invoice-decision",
      "uri": null,
      "content": {
        "invoice_number": "INV-123",
        "decision": "approved"
      },
      "business_artifact": {
        "source": "erp:production:invoices",
        "external_id": "INV-123"
      }
    }
  ],
  "metadata": {
    "environment": "production",
    "queue": "accounts-payable"
  }
}
```

### Run fields

| Field        | Type               | Required | Description                                                                                                          |
| ------------ | ------------------ | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `run_id`     | string             | Yes      | Stable execution identifier, 1–200 characters. Reuse it only to retry the same evidence.                             |
| `executor`   | object             | Yes      | Stable executor identity and type displayed for the automated actor.                                                 |
| `name`       | string             | Yes      | Descriptive workflow name, 1–500 characters. Fluency uses it as process-matching evidence.                           |
| `started_at` | RFC 3339 timestamp | Yes      | Timezone-aware start of the complete workflow execution.                                                             |
| `ended_at`   | RFC 3339 timestamp | Yes      | Timezone-aware end of the execution. Must be on or after `started_at`.                                               |
| `status`     | string             | Yes      | `completed` or `failed`. Running or partial executions are not accepted.                                             |
| `steps`      | array              | Yes      | Zero to 1,000 measured steps. Step IDs must be unique within the run.                                                |
| `artifacts`  | array              | Yes      | Zero to 100 execution artifacts. Artifact IDs must be unique within the run.                                         |
| `process_id` | string             | No       | Exact existing Fluency process ID. Most customer integrations omit this and let Fluency match or create the process. |
| `metadata`   | object             | No       | JSON-compatible customer metadata. Defaults to `{}`.                                                                 |

Unknown fields are rejected.

### Executor fields

| Field     | Type             | Required | Description                                                                                                          |
| --------- | ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------- |
| `type`    | string           | Yes      | `agent`, `automation`, or `service`. This controls the actor label shown in Fluency.                                 |
| `id`      | string           | Yes      | Stable workflow identity, 1–200 characters. Keep it constant across executions and deployments of the same workflow. |
| `name`    | string           | Yes      | Customer-facing workflow name, 1–500 characters.                                                                     |
| `version` | string or `null` | No       | Your workflow, model, or deployment version.                                                                         |

For the organization API key flow, the submitted executor identity describes the workflow while the verified credential independently determines the organization and authorization.

### Step fields

| Field        | Type               | Required | Description                                                       |
| ------------ | ------------------ | -------- | ----------------------------------------------------------------- |
| `step_id`    | string             | Yes      | Unique identifier within the run, 1–200 characters.               |
| `name`       | string             | Yes      | Meaningful customer-facing step name, 1–500 characters.           |
| `kind`       | string             | Yes      | `tool`, `llm`, `step`, or `log`.                                  |
| `started_at` | RFC 3339 timestamp | Yes      | Timezone-aware start within the parent run interval.              |
| `ended_at`   | RFC 3339 timestamp | Yes      | Timezone-aware end within the run and on or after the step start. |
| `status`     | string             | Yes      | `completed` or `failed`.                                          |
| `input`      | any JSON value     | No       | Input used by the step.                                           |
| `output`     | any JSON value     | No       | Output produced by the step.                                      |
| `error`      | string or `null`   | No       | Error message for a failed step.                                  |

Steps may overlap or nest. Fluency calculates handling time from the union of measured step intervals so concurrent work is not counted twice.

### Artifact fields

| Field               | Type             | Required | Description                                                                                                                                            |
| ------------------- | ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `artifact_id`       | string           | Yes      | Unique evidence identifier within the run, 1–200 characters.                                                                                           |
| `name`              | string           | Yes      | Customer-facing artifact name, 1–500 characters.                                                                                                       |
| `kind`              | string           | Yes      | Customer-defined artifact category, 1–200 characters.                                                                                                  |
| `uri`               | string or `null` | No       | Reference to the source object. Fluency stores the reference and does not fetch arbitrary remote files.                                                |
| `content`           | any JSON value   | No       | Snapshot or structured result to retain as execution evidence.                                                                                         |
| `business_artifact` | object           | No       | Stable identity that connects this evidence to the same invoice, ticket, claim, case, order, or other object handled by people or automated workflows. |

An execution artifact records what this particular run produced or observed. A business artifact identifies the underlying object across many human and automated executions.

### Business artifact identity

Use one of these forms:

Known Fluency artifact ID:

```json theme={"system"}
{
  "id": "existing-fluency-artifact-id"
}
```

Namespaced source-system identity:

```json theme={"system"}
{
  "source": "erp:production:invoices",
  "external_id": "INV-123"
}
```

Register a source-system identity against a known Fluency artifact:

```json theme={"system"}
{
  "id": "existing-fluency-artifact-id",
  "source": "erp:production:invoices",
  "external_id": "INV-123"
}
```

`source` and `external_id` must be supplied together. Make `source` specific enough to separate systems, environments, accounts, and record types. Display names are not stable identity.

If no explicit business identity is supplied, Fluency may use exact structured identifiers and tenant-local semantic evidence. Ambiguous or conflicting evidence remains unlinked rather than merging unrelated objects.

### Limits and validation

* Maximum request body: 2 MiB.
* Maximum steps: 1,000.
* Maximum artifacts: 100.
* Run, step, and artifact timestamps must be timezone-aware and ordered.
* Every step interval must fall within the run interval.
* Completed or failed runs cannot contain running steps.
* IDs must be unique within the run.
* All values must be valid JSON.

The SDK applies a smaller default snapshot limit of 1 MiB so it can reject oversized evidence before delivery.

### Acceptance response

New evidence:

```json theme={"system"}
{
  "run_id": "invoice-job-018f6f6e",
  "status": "accepted"
}
```

An identical retry:

```json theme={"system"}
{
  "run_id": "invoice-job-018f6f6e",
  "status": "duplicate"
}
```

Both responses use HTTP `200`. `accepted` means Fluency durably stored the evidence. It does not mean asynchronous process matching has finished.

## Check processing status

```http theme={"system"}
GET /ext/workflow-telemetry/runs/{run_id}
```

```bash theme={"system"}
curl \
  "$FLUENCY_WORKFLOW_ENDPOINT/ext/workflow-telemetry/runs/invoice-job-018f6f6e" \
  --header "Authorization: Bearer $FLUENCY_WORKFLOW_API_KEY"
```

Example response:

```json theme={"system"}
{
  "run_id": "invoice-job-018f6f6e",
  "processing_status": "ready",
  "process_id": "process_01JZ8E4M5A",
  "processing_error": null,
  "projection": {
    "description": "Reads, validates, and approves a supplier invoice.",
    "association": {
      "method": "semantic",
      "reason": "The measured steps align with the existing invoice process.",
      "confidence": 0.93
    }
  }
}
```

| Status       | Meaning                                                                  |
| ------------ | ------------------------------------------------------------------------ |
| `pending`    | Stored and waiting for processing, or waiting for an automatic retry.    |
| `processing` | A worker is matching the process and reconciling artifacts.              |
| `ready`      | Projection succeeded and the execution can appear in the product.        |
| `failed`     | Processing exhausted its automatic retries. Raw evidence remains stored. |

`process_id` can be `null` until association succeeds. `projection` contains enrichment details and may gain fields during the private preview; clients should use `processing_status` and `process_id` for control flow.

An organization API key can check runs submitted to its organization.

## Idempotency and retries

`run_id` is the idempotency key across the organization.

* Retry the exact same payload with the same `run_id` after a timeout or temporary server error.
* An identical payload returns `duplicate` and does not create another execution.
* Different evidence under an existing `run_id` returns HTTP `409`.
* Use a new `run_id` for every distinct execution, including a business-level retry that actually ran the workflow again.

Use exponential backoff with jitter for network errors and HTTP `5xx` responses. Do not automatically retry other `4xx` responses without correcting the request or credential.

## Errors

Errors return a JSON body with a human-readable `detail` field.

| HTTP status | Meaning                                                                                        | Typical action                                                          |
| ----------- | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| `400`       | Invalid body, timestamp, status, interval, ID, or business artifact reference.                 | Correct the evidence before retrying.                                   |
| `401`       | Missing, malformed, invalid, expired, or wrong-owner credential.                               | Replace or refresh the credential.                                      |
| `403`       | Missing `workflow-telemetry:write`, or the organization is not enabled.                        | Ask the Fluency administrator to check access.                          |
| `404`       | Explicit process, artifact, or requested run does not exist in the authenticated organization. | Correct the identifier or omit optional explicit association.           |
| `409`       | Existing run ID has different evidence, or business artifact identifiers conflict.             | Use the original evidence or a new run ID; reconcile artifact identity. |
| `413`       | Request exceeds 2 MiB.                                                                         | Reduce captured content or use SDK metadata-only mode.                  |
| `5xx`       | Temporary Fluency, authentication-provider, or database failure.                               | Retry with exponential backoff and jitter.                              |

Never log the bearer credential while recording or reporting an error.

## Process matching

Most customers should omit `process_id`. Fluency attempts association in this order:

1. An explicit valid `process_id`, when supplied.
2. A unique normalized workflow-name match.
3. Grounded semantic matching against candidate processes in the authenticated organization.
4. Creation or reuse of a workflow process when no safe existing match is available.

Fluency does not attach a run to a process when the evidence is uncertain. A matched human process keeps its existing process ID, allowing human and automated executions to appear together.

## Delivery and privacy

* The API accepts final snapshots, not live partial updates or arbitrary OTLP streams.
* Inputs, outputs, artifact content, URIs, and error messages are stored when supplied.
* Do not include credentials or secrets in captured evidence.
* Omit sensitive values or use the SDK's `captureContent: false` / `capture_content=False` mode.
* Processing failures do not delete the raw accepted evidence.
* The current API does not provide a customer endpoint for deleting individual runs.

## SDK equivalents

TypeScript:

```ts theme={"system"}
import { init } from '@fluency/workflow-telemetry';

const fluency = init({
  endpoint: process.env.FLUENCY_WORKFLOW_ENDPOINT!,
  executor: { type: 'automation', id: 'accounts-payable-workflow', name: 'Accounts payable workflow' },
});

await fluency.run('Process supplier invoice', async (run) => {
  await run.step('Approve invoice', approveInvoice, { kind: 'tool' });
});

await fluency.shutdown();
```

Python:

```python theme={"system"}
from fluency_workflow_telemetry import init

fluency = init(
  endpoint=os.environ["FLUENCY_WORKFLOW_ENDPOINT"],
  executor={"type": "automation", "id": "accounts-payable-workflow", "name": "Accounts payable workflow"},
)

with fluency.run("Process supplier invoice") as run:
  with run.step("Approve invoice", kind="tool") as step:
    step.output = approve_invoice()

fluency.shutdown()
```

See [Fluency AI Agent SDKs](/fluency-ai-agent-sdks) for installation, LangChain callbacks, OpenTelemetry adapters, delivery guarantees, and release-package verification.

## Support information

When contacting Fluency, provide:

* Fluency organization name;
* `executor.id`;
* `run_id`;
* approximate UTC timestamp;
* endpoint region;
* SDK language and version, if applicable; and
* HTTP status and error `detail`.

Never send the API key.
