---
title: "Write cached lens output into a photo's EXIF/IPTC/XMP metadata"
method: POST
path: "/v2/enrich"
tags: ["Registry"]
---

# Write cached lens output into a photo's EXIF/IPTC/XMP metadata

`POST /v2/enrich`

## Request

- Base URL: `https://api.phototology.com`
- URL: `https://api.phototology.com/v2/enrich`
- Auth: HTTP bearer

Embeds cached lens output (from a prior `/v2/analyze` call) into the photo's EXIF/IPTC/XMP metadata blocks so the analysis travels with the file. The enriched bytes carry their structured intelligence in standard metadata fields any downstream tool can read, with no further Phototology call required to access the analysis.

### Source-of-truth gate
Requires a cached registry entry for the `(userId, sha256)`. If the photo has not been analyzed before, returns 404 `PHOTO_NOT_IN_REGISTRY`. The endpoint does NOT trigger analysis; call `POST /v2/analyze` first.

### Cost
5 credits per call. Matches the bespoke schema extraction tier. Bills regardless of cache state; the write-back work is its own billable operation.

### C2PA signing
Deferred. `c2pa` in the `formats` array is rejected at validation time with a structured deferred-feature message. Provenance signing requires the Railway `c2patool` binary, a CA-chained cert, and a KMS-backed key (see `packages/phototology/CLAUDE.md` Sprint 3 follow-ups). Use `["exif", "iptc", "xmp"]` for now.

## Request body

- object
  - `imageUrl` string, uri
  - `imageBase64` string
  - `formats` string[], required
  - `preserveCredentials` boolean

## Response `200`

Enriched photo returned as base64 in the response body. The caller decodes and saves to disk.

- object
  - `object` 'enrichment', required
  - `mode` 'file' | 'sidecar', required
  - `imageBase64` string
  - `sidecar` object
    - `xmp` string, required
  - `formatsWritten` string[], required
  - `reason` string
  - `warnings` string[]
  - `credentials` object, required
    - `status` 'none' | 'invalid' | 'valid' | 'trusted' | 'unread', required
    - `aiGenerated` boolean, nullable, required
    - `signer` object, nullable, required
      - `name` string, required
      - `issuer` string, required
    - `captureDevice` string, nullable, required
    - `signedAt` string, nullable, required
    - `trustList` 'c2pa' | 'legacy', nullable, required
    - `assertions` string[], required
    - `note` string, required
  - `lensVersions` object, required
  - `sha256` string, required
  - `registryId` string
  - `meta` object, required
    - `requestId` string, required
    - `processingTimeMs` integer, required
    - `creditsCharged` integer, required
    - `ai_generated` true, required

## Other responses

- `400`: Validation failed (missing image, both image inputs supplied, unknown format, or `c2pa` requested, which is deferred).
- `401`: Missing or invalid API key, or key lacks a userId.
- `402`: Insufficient credits (5 needed). Same shape as analyze: `error.credits` carries the breakdown.
- `404`: Photo not in the registry for this account. Call `POST /v2/analyze` first.
- `422`: Image bytes invalid or fetch failed.

---

[API](https://skmtc.dev/phototology/apis/phototology-api.md) · [All operations](https://skmtc.dev/phototology/apis/phototology-api/llms.txt) · [OpenAPI document](https://skmtc.dev/phototology/apis/phototology-api/revisions/3cb0fc707b63?raw)
