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

# Incoming items

> What a sending system delivers to ContentFlow — workflow name, trace ID, batch, properties and the file — and how to confirm that an item was processed.

Every document enters ContentFlow as an **item**: a file plus the metadata a sending system knows about it. The item names the workflow that should process it. A [document mapping](/contentflow/document-mappings) later reads the item's properties to decide what Nobly Insight receives. Agree on the item contract with the team that builds the sending integration before you build the workflow and the mapping.

## Prerequisites

The sending system calls the ContentFlow API with a token from your environment's identity provider. Give each integration its own identity, for example a dedicated [API client](/integrations/api-clients), so you can rotate or disable it without affecting other integrations.

The submission endpoints accept any identity your environment authenticates; they do not check ContentFlow permissions. ContentFlow permissions govern the ContentFlow application and its administration, not who may submit.

## What an item carries

| Field | Required | Meaning |
| - | - | - |
| **WorkflowName** | Yes | The ContentFlow workflow that processes the item. A submission naming no workflow, or a workflow that does not exist, is rejected. |
| **TraceId** | Yes | A new GUID per submission, chosen by the sender. It identifies the item everywhere: in States, in logs, and in reruns. A trace ID that already exists is rejected. |
| **BatchName** | No | Groups related items, such as one night's export, so you can follow and rerun them together. Don't use `Testing`: items in that batch run mapping drafts. |
| **ItemTypeName** | No | The sender's document type. A mapping uses it when its document type comes **From the sender**. |
| **ContentDateTime** | No | The document date the sender knows. A mapping uses it when its document date comes **From the sender**. |
| **Properties** | No | The metadata, as a list of name and value pairs. See [Properties and property groups](#properties-and-property-groups). |
| The file | Yes, unless metadata-only | The document itself, with its file name and MIME type |

### Properties and property groups

Each property has a **Name** and a **Value**. Send the same name more than once to deliver several values. A mapping row then writes one keyword value per value, unless the row keeps only the first.

To deliver repeating structured data, such as several policies on one letter, give the properties that belong together the same **GroupName** and **GroupIdentifier**. All properties of one policy share a group identifier; the next policy uses another. A mapping turns each group instance into a keyword record of the type you choose.

Keep property names stable. A mapping reads properties by name (letter case is ignored), so a renamed property can silently stop reaching its keyword. Try it in the mapping editor lists properties that no row reads, which shows a rename quickly.

### Metadata-only items

An item can arrive without a file when the file is fetched later by the workflow, for example from a storage export during a migration. Mark the submission as **metadata-only**, include at least one property, and optionally the file name and MIME type the document should get. The workflow then starts with a step such as **Fetch file from Azure Blob**; see the [step reference](/contentflow/steps#get-or-convert-the-file).

## Submit an item

The ContentFlow API accepts an item in two forms:

| Endpoint | Body |
| - | - |
| `POST /api/items` | A multipart form with the fields above and the file in `FormFile`. Properties are sent as indexed form fields: `Properties[0].Name`, `Properties[0].Value`, and so on. |
| `POST /api/items/base64` | A JSON body with the file content as base64 in `FileInfo` |

The API publishes its OpenAPI description and an interactive reference at `/swagger` on its address. Use that reference for your environment's version rather than inferring fields from an example.

A JSON submission of a one-page policy schedule with two properties looks like this:

```json theme={null}
{
  "workflowName": "Policy documents",
  "traceId": "7c0e5d0a-3b1f-4f3e-9a51-2f6a1b9e8d40",
  "batchName": "Policy export 2026-10-01",
  "contentDateTime": "2026-09-14T00:00:00+02:00",
  "fileInfo": {
    "fileName": "policy-0001.pdf",
    "contentMimeType": "application/pdf",
    "base64Content": "<the file, base64-encoded>"
  },
  "properties": [
    { "name": "DocumentCategory", "value": "POLICY_SCHEDULE" },
    { "name": "CustomerNo", "value": "4471" }
  ]
}
```

| Response | Meaning |
| - | - |
| **204 No Content** | The item was accepted and queued for its workflow |
| **400 Bad Request** | The submission is incomplete, its file content is not valid, or it names a workflow that does not exist. The message says what is wrong. The item was not queued. |
| **409 Conflict** | The trace ID already exists. Send a new trace ID for a new document; to process an existing item again, [rerun it](/contentflow/states-and-recovery#rerun-failed-runs) instead. |

<Warning>
  Accepted is not the same as archived. A 204 response means ContentFlow has the item, not that the workflow completed or that Nobly Insight received the document.
</Warning>

## Confirm the outcome

The sending system can ask for an item's state with `GET /api/items/state/{traceId}`. The response contains the state (`Pending`, `Started`, `Completed`, `Failed` or `ScheduledRetry`), the error message of a failed run, the batch name, and any result properties the workflow recorded. A workflow records result properties with its **Add state result property** step, for example the document ID Nobly Insight assigned.

The same runs appear in the ContentFlow application under [States](/contentflow/states-and-recovery), where you can read each run's logs and the document that was sent. A sending system that needs a push notification instead of polling can be called back by a **Webhook callback** step after the upload; see the [step reference](/contentflow/steps#call-other-systems).

## Verify a new integration

Before you switch a sending system on in production, submit a handful of representative items in a test environment:

| Test | Expected result |
| - | - |
| A normal item for each document type the sender produces | Completed runs, and documents in Nobly Insight with the expected type, date and keywords |
| An item with a mandatory property missing | A failed run whose message names the property, not a document archived with a gap |
| An item naming a workflow that does not exist | A 400 response; nothing stored |
| The same trace ID sent twice | A 409 response for the second submission |
| A batch of items | Every item visible in the batch on the States page |

## Where to read next

<Card title="Document mappings" icon="arrows-left-right" href="/contentflow/document-mappings" horizontal>
  Define in one place what Nobly Insight receives for each incoming item: its document type, its document date, and one row per keyword.
</Card>

<Card title="API clients and service accounts" icon="plug" href="/integrations/api-clients" horizontal>
  Create a dedicated machine identity for a sending system, and rotate or disable it independently.
</Card>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.