Ingredients
An ingredient is a prior asset bound into the manifest: the parent a derivative was made from, or a component composited in. Chaining ingredients across signing stages forms a provenance chain, where each manifest names its parent and a verifier walks the chain backward.
You never set an ingredient's relationship directly. You state provenance facts — where the asset came from and what was brought into it — and the signer derives each ingredient's C2PA relationship (parentOf, componentOf, inputTo) and the lifecycle action that goes with it.
The Ingredient shape
Everywhere an ingredient appears (origin.parent or a Component.asset) it is the same object:
| Field | Required | Meaning |
|---|---|---|
data | yes | The ingredient's bytes (typically already signed). The SDK extracts its C2PA manifest client-side and sends only that, never the full asset. |
format | no | Explicit MIME for a container the SDK can't sniff; inferred from data otherwise. |
title | no | Human-readable title override for provenance-less ingredients. |
thumbnail | no | A preview tile for this ingredient. See Thumbnails. |
Where an ingredient goes
The signer decides the relationship from where you place the ingredient in the request:
- Parent →
origin: { parent }. The asset was derived from this one; the signer adds it as theparentOfingredient and derivesc2pa.opened. An edit names its source capture; a re-encode names its original. - Placed component → a
Componentwithevent: "placed". An asset composited or assembled into this one; the signer derivescomponentOf+c2pa.placed. Useevent: "removed"for something taken out. - Input → a
Componentwithevent: "inputTo". An asset that fed a process (for example source frames fed to an AI generation step); the signer derives theinputTorelationship and no action.
Parent (a derivative)
const { sidecar } = await sdk.sign(edited, "edited.jpg", {
origin: { parent: { data: captureSigned } },
actions: [{ kind: "edited" }],
}, { storage: { mode: "embedded" } });
Components (composited in)
Each component has a caller-chosen id; workflow actions can reference that id through componentIds to say which components an action acted on.
const { sidecar } = await sdk.sign(composite, "composite.jpg", {
origin: { sourceType: "digitalCreation" },
components: [
{ id: "logo", asset: { data: logoSigned }, event: "placed" },
{ id: "backdrop", asset: { data: backdropSigned }, event: "placed" },
],
actions: [{ kind: "edited", componentIds: ["logo", "backdrop"] }],
}, { storage: { mode: "embedded" } });
Provenance chains across edits
Re-encoding is where the chain earns its keep. Any transformation that rewrites the asset bytes (a transcode, a format conversion, a destructive edit) invalidates the parent's embedded manifest, because the manifest's data hash no longer matches the new bytes. The parent is not lost: it is carried forward as the origin.parent ingredient on the new manifest. The new manifest attests the new bytes; the ingredient preserves the link to the validated parent. See the newsroom sidecar chain for a worked three-stage example.
Streams
Live streams chain manifests across signing key epochs rather than across edits, but the principle is the same: each epoch's init manifest references the prior one through origin.parent. See Key rotation.
See also
- Thumbnails: preview tiles for the claim and for each ingredient.
- Assertions: why actions and relationships are facts, not assertions.
- Newsroom sidecar chain: a three-stage provenance chain.
- Key rotation: manifest chaining for live streams.