# From submission to data delivery


This page follows one piece of work from the moment a Contributor submits it to the moment your API read returns it, and shows where to look when it does not arrive. Along the way it is submitted, accepted, delivered, authorized, and finally read by you; those are distinct states, and each of them can hold it up.

Use **Campaign → Reviews → Review** to inspect individual work. Configure the workflow and fields in Builder. Use an [authorized API request](/api/api-data) for programmatic delivery.

## Choose the delivered fields

An **ETL** step decides which fields an API consumer receives for each accepted record, and under which names. It changes nothing in the original Submission: **Campaign → Reviews → Review** still shows what the Contributor submitted.

1. In the Campaign **Builder**, add an **ETL** step between **Accept** and **Sink**, then double-click it to open its panel.
2. Under **Delivered fields**, each row reads one or more **Form fields** into one **API field**. Before you edit anything, the table only shows the default: saving now delivers every form field unchanged, including fields the form gains later. Your first edit turns the table into the list of delivered fields.
3. To rename a field, type the new name in its API field — for example, `category` in the `answer` row. To stop delivering a field, remove its row (×). A field the form collects but the list leaves out appears under **Collected but not delivered**: select **Deliver it too** to add it back, or turn on **Also deliver form fields this mapping does not name** to pass every unlisted field through under its own name.
4. Open a row's options (⌄) to set **Required**, which holds back a record that has no value, or a **Default when empty**. To read a second form field into the same API field, add it with **+ field**: the two values are joined, unless you turn on **Fallback**, which takes the first one that has a value.
5. Select **Try a sample**, type what a Contributor might submit, and compare **Delivered shape** with what your consumer expects. A blank sample field counts as not collected; while every field is blank, the preview shows each field's name instead of a value. The preview does not show everything delivery does: with **Also deliver form fields this mapping does not name** on, the record also carries every other field the Contributor filled, under its own name; and a record is held back, not delivered, when a **Required** row has no value and no default, or when a value is not listed while **Hold the record back on a value that is not listed above** is on — the preview still shows such a record.
6. Select **Save**. Save stays unavailable while red text in the panel names a problem, such as a field without a name or two fields with the same name. Saving the step saves the Campaign's workflow; there is no separate canvas save. On a running Campaign, Save first asks you to confirm the change.

For this illustrative mapping, a Review showing `answer: "fruit"` corresponds to `data.category: "fruit"` in an eligible delivered record. If `answer` is empty, the sample preview omits `category` unless you set a default. Check the actual record in [the API response](/api/api-data) before treating the preview as proof of delivery.

**Reset to form fields** lists every form field again, but as a list: a field the form gains later is not delivered unless **Also deliver form fields this mapping does not name** is on. Removing every row goes back to the default. Check each workflow branch separately.

Before changing a mapping already used by consumers, compare its output field names and missing-value rules with their expected schema. Test a new delivered record and check how historic records or exports behave for that Campaign; changing the mapping does not rewrite original Submissions or establish that older delivered records were backfilled.

## Sink, subscription, and API

The accepted branch can connect directly to **Sink** or pass through ETL first. Sink stores workflow output; its JSON and CSV settings do not generate a downloadable file by themselves.

The API can return a submission only after it is accepted and the Contributor's reward is recorded. Even then, you see it only if your subscription and filters include it. A successful Sink save alone cannot prove that a subscription has readable records; the absence of a Sink alone cannot explain every empty API result.

For a particular Submission, follow this order:

| What you find | Check next |
| --- | --- |
| No accepted result in **Campaign → Reviews → Review** | Inspect the review outcome and feedback before investigating delivery. |
| Accepted, but reward grant is unknown | The Contributor can check that Submission's **Activity** or **Awarded** record. If you cannot see its reward state, ask support to check it by Submission ID. |
| Reward granted, but the [small API read](/api/api-data) is empty | Confirm the same organization's Subscription ID, its scope, the selected mode and filters. If these match, ask support to trace delivery for that Submission. |
| API returns a record | Match its `submission_id` and `data` to the Review and agreed mapping before using it. |
| The records disagree, or you cannot locate the missing stage | Send the Campaign, Submission and Subscription IDs and the observed status to [support](/help/support). Keep API Keys and private submitted content out of the request. |

The API response establishes what this subscription actually returned.

## Chain references and actual files

An on-chain anchor records identifiers, digests, and file references. Original files and metadata are usually held off-chain. A hash helps verify content consistency; a URI locates referenced content. Finding a chain record does not give you the original file or permission to use it, and does not establish that every file is encrypted or permanently stored. Continue with [provenance](/data/lineage) and [data rights](/data/rights).
