Recipes
Recipes
A recipe is a YAML document that configures exactly what happens when you call POST /v1/sign or POST /v1/verify. It controls which watermark engine to use, which C2PA assertions to include, anchoring tier, manifest retention, and billing meter.
Built-in presets
Verbitas ships 10 preset recipes. They are immutable after the release tag.
| Recipe ID | Media type | C2PA | Watermark | Anchoring | Use case |
|---|---|---|---|---|---|
image-genai-v1 | image | required | TrustMark | OTS Tier 1 | Standard AI image |
image-editorial-v1 | image | required | TrustMark | OTS + Arbitrum | Editorial photography |
image-deepfake-v1 | image | required + deepfake assertion | TrustMark | OTS + Arbitrum | Deepfake disclosure |
image-legal-evidence-v1 | image | required | TrustMark | 5-min OTS + Arbitrum | Legal chain of custody |
audio-genai-v1 | audio | required | AudioSeal | OTS Tier 1 | AI-generated audio |
audio-voiceclone-v1 | audio | required + voiceclone assertion | AudioSeal | OTS + Arbitrum | Voice clone disclosure |
video-genai-v1 | video | required | VideoSeal | OTS Tier 1 | AI-generated video |
video-advertising-v1 | video | required | VideoSeal | OTS + Arbitrum | Advertising provenance |
text-genai-disclosure-v1 | text | required (sidecar) | SynthID-Text | OTS Tier 1 | LLM text disclosure |
enterprise-strict-v1 | any | required | all applicable | OTS + Arbitrum + BYOC | BYOK KMS, enterprise |
Recipe YAML structure
id: my-image-pipeline-v1 # unique ID; convention: <slug>-v<N>version: 1 # starts at 1; increment on each changeextends: image-genai-v1@1 # base preset to extend (required for custom recipes)media_type: image # image | audio | video | textdescription: My image pipeline provenance
c2pa: enabled: true # must be true for ai_generated: true content assertions: - ai_generated - generator - model - created_at require_ingredient_chain: false # set true for editorial / legal-evidence
watermark: enabled: true engine: trustmark # trustmark | audioseal | videoseal | synthid_text payload: type: manifest_pointer encoding: compact
soft_binding: enabled: true methods: - exact_watermark # exact_watermark | exact_hash | perceptual_hash - perceptual_hash
anchoring: enabled: true methods: - opentimestamps # opentimestamps | arbitrum batch_interval_minutes: 60 # 5 = legal-evidence fast anchor; 60 = standard
kms_mode: kms # kms (default) | byok | dev_local
retention: manifest_days: 365 # how long to keep the manifest original_asset_days: 0 # 0 = do not store original asset derived_asset_days: 30 # 0 = do not store derived (signed) asset
verification: minimum_confidence: 0.92 ocsp_mode: default # default | required ambiguous_match_behavior: manual_review # manual_review | reject | accept_partial
billing: meter: image_sign # see Reference: Meter Kinds unit: asset
ui: public_label: "AI-generated image with verifiable provenance"Step kinds (closed enum)
A recipe specifies which operations run, but the operations themselves are a closed enum. You cannot add new step kinds without an RFC in docs/rfcs/. The current valid values are:
| Step kind | What it does |
|---|---|
c2pa_build | Constructs the C2PA claim structure from assertions and metadata |
watermark_embed | Runs the watermark engine to embed the payload in the asset signal |
soft_binding_write | Writes the fingerprint index entry (exact hash, pHash, watermark_id) |
anchor_queue | Enqueues the manifest digest for the next anchor batch |
c2pa_finalize | Calls the signer, receives signature + cert chain + timestamp, assembles JUMBF manifest |
These steps run in the order above during every sign job. The recipe controls whether each step is active and which parameters it uses — not the order.
Custom recipes
Custom recipes must extend one of the 10 presets using the extends field. They are validated against packages/recipes/schema/recipe.schema.json on submission.
Custom recipes are immutable after first use. If an asset was signed with my-recipe-v1, it will always verify against my-recipe-v1. To change the recipe, create my-recipe-v2.
Create via API
Requires admin-scoped key.
curl -X POST https://api.verbitas.io/v1/recipes \ -H "Authorization: Bearer vb_admin_..." \ -H "Content-Type: application/yaml" \ --data-binary @my-image-pipeline-v1.yamlResponse:
{ "recipe_id": "my-image-pipeline-v1", "version": 1, "created_at": "2026-05-09T10:00:00Z" }Errors
| Code | Meaning |
|---|---|
verbitas.recipes.invalid_schema | YAML does not pass recipe.schema.json validation |
verbitas.recipes.unknown_step_kind | step.kind outside closed enum |
verbitas.recipes.byok_plan_required | kms_mode: byok requires Enterprise BYOK plan |
verbitas.recipes.conflict | Recipe ID + version already exists |
Recipe selection guide
| Use case | Recipe |
|---|---|
| AI-generated image | image-genai-v1 |
| Editorial photography | image-editorial-v1 |
| Deepfake disclosure required | image-deepfake-v1 |
| Legal chain of custody | image-legal-evidence-v1 |
| AI-generated audio / TTS | audio-genai-v1 |
| Voice clone disclosure | audio-voiceclone-v1 |
| AI-generated video | video-genai-v1 |
| Advertising video provenance | video-advertising-v1 |
| LLM text disclosure | text-genai-disclosure-v1 |
| Enterprise, BYOK, all anchors | enterprise-strict-v1 |
| Custom | POST /v1/recipes with extends: |
See Guides: Custom Recipes for a complete walkthrough of writing a custom recipe.