REST API

Integrate JPEG Trust into any application over HTTP. Embed, extract, and verify provenance metadata via simple multipart requests.

Base URL

https://16.61.203.65/rest

Interactive API explorers: Swagger UI (try requests in the browser) and ReDoc. The OpenAPI description is at /rest/openapi.json. A local backend serves the same pages at /docs and /redoc.

Authentication

No authentication is required for local or private deployments. For public-facing instances, configure API key authentication at the reverse proxy level.

Extract metadata

POST
/extract

Extract provenance metadata from a JPEG or PNG image. Tries JUMBF JSON first, then falls back to binary manifests.

Request

Multipart form data with one field:

FieldTypeDescription
image file JPEG or PNG image file
Response 200

JSON indicator object with declaration, assertions, and manifests.

curl
curl -X POST https://16.61.203.65/rest/extract \
  -F "image=@photo.jpg"
Python
import requests

resp = requests.post(
    "https://16.61.203.65/rest/extract",
    files={"image": open("photo.jpg", "rb")},
)
metadata = resp.json()
JavaScript
const form = new FormData();
form.append("image", fileInput.files[0]);

const resp = await fetch("https://16.61.203.65/rest/extract", {
  method: "POST",
  body: form,
});
const metadata = await resp.json();
Example response
{
  "@context": ["https://jpeg.org/jpegtrust/"],
  "declaration": {
    "claim": {
      "alg": "sha256",
      "claim_generator_info": [{ "name": "Joe's Camera App" }],
      "signature_status": "claimSignature.validated",
      "content_status": "assertion.dataHash.match"
    },
    "assertions": {
      "cawg.metadata": {
        "@context": { "dc": "http://purl.org/dc/elements/1.1/" },
        "dc:creator": ["Jane Doe"]
      },
      "c2pa.actions.v2": {
        "actions": [{
          "action": "c2pa.created",
          "digitalSourceType": "http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"
        }]
      }
    }
  },
  "manifests": [...]
}

Embed metadata

POST
/embed

Embed provenance metadata into a JPEG or PNG image. Returns the modified image as a binary download.

Request
FieldTypeDescription
image file JPEG or PNG image file
metadata file JSON metadata file
digital_source_type string Optional. IPTC source type slug (e.g. trainedAlgorithmicMedia)
Response 200

Binary image file (image/jpeg or image/png) with embedded metadata.

curl
curl -X POST https://16.61.203.65/rest/embed \
  -F "image=@photo.jpg" \
  -F "metadata=@metadata.json" \
  -F "digital_source_type=digitalCapture" \
  -o embedded.jpg
Python
import requests

resp = requests.post(
    "https://16.61.203.65/rest/embed",
    files={
        "image": open("photo.jpg", "rb"),
        "metadata": open("metadata.json", "rb"),
    },
    data={"digital_source_type": "digitalCapture"},
)
with open("embedded.jpg", "wb") as f:
    f.write(resp.content)

Verify image

POST
/verify

Verify an image against a trust profile. Returns a scored verification report.

Request
FieldTypeDescription
image file JPEG or PNG with embedded metadata
profile file YAML trust profile
Response 200
status pass (≥ 95%), warning (≥ 70%), or fail
score Fraction of checks passed (0.0 – 1.0)
verdict trusted, mostly_trusted, or profile_mismatch
passed / failed Arrays of check IDs
c2pa Signature and content-hash validation details
ai_label AI generated, AI modified, not AI-labelled, or unknown
curl
curl -X POST https://16.61.203.65/rest/verify \
  -F "image=@signed.jpg" \
  -F "profile=@newsroom_profile.yml"
Example response
{
  "status": "pass",
  "score": 0.9167,
  "verdict": "trusted",
  "profile": "Newsroom Trust Profile",
  "passed_checks": 10,
  "total_checks": 11,
  "passed": ["signature_chain", "capture_timestamp", ...],
  "failed": ["gps_location"],
  "ai_label": "not AI-labelled",
  "c2pa": {
    "detected": true,
    "validation": "valid",
    "signature_valid": true,
    "content_intact": true
  }
}

Validate record

POST
/validate

Run the offline JPEG Trust validator on one image. Returns its full report and the verdict of the selected checks (see the validator docs). GET /validate/config reports whether the server has default trust anchors.

Request
FieldTypeDescription
image file JPEG or PNG with an embedded Trust Record
trust-anchors file Optional PEM bundle of CA certificates for signer (and TSA) trust
use-default-anchors boolean Use the server's trust anchors instead of an upload
require-trust boolean Include signer trust in the verdict (needs anchors)
require-conformance boolean Include JPEG Trust conformance in the verdict
identity-trust-anchors, timestamp-anchors file Optional report-only PEM bundles
Response 200
verdict pass, fail or incomplete
exit_code The validator CLI's exit code for the same options (0, 1 or 3)
trust_anchor_source uploaded, the server default, or null
report The validator report (schema 1.0): embedding, integrity, trust and conformance assessments with every check
curl
curl -X POST https://16.61.203.65/rest/validate \
  -F "image=@signed.jpg" \
  -F "use-default-anchors=true" \
  -F "require-trust=true" -F "require-conformance=true"

Batch operations

Process multiple images in a single request. All batch endpoints accept multiple files via the images form field.

POST
/batch/extract

Extract metadata from multiple images. Returns a JSON array with per-image results and a count of how many had metadata.

curl
curl -X POST https://16.61.203.65/rest/batch/extract \
  -F "images=@photo1.jpg" \
  -F "images=@photo2.jpg" \
  -F "images=@photo3.png"
POST
/batch/embed

Embed metadata into multiple images. Returns a ZIP archive containing all embedded images.

FieldTypeDescription
images file[] One or more JPEG/PNG files
metadata file JSON metadata applied to all images
digital_source_type string Optional IPTC source type slug
POST
/batch/verify

Verify multiple images against one trust profile. Returns per-image results and a summary with pass/warning/fail/error counts.

curl
curl -X POST https://16.61.203.65/rest/batch/verify \
  -F "images=@photo1.jpg" \
  -F "images=@photo2.jpg" \
  -F "profile=@newsroom.yml"
Example response
{
  "results": [
    { "filename": "photo1.jpg", "status": "pass", "score": 0.92, "verdict": "trusted" },
    { "filename": "photo2.jpg", "status": "fail", "score": 0.33, "verdict": "profile_mismatch" }
  ],
  "summary": { "total": 2, "passed": 1, "warnings": 0, "failed": 1, "errors": 0 }
}

Profiles

Browse available trust profiles and create new ones from templates or custom check lists.

GET
/profiles/templates

Returns a map of template names to their included check IDs.

TemplateChecksUse case
newsroom11Wire photos, editorial
insurance6Claims photo validation
creator6Artist authenticity & rights
ai-labelling7AI content detection
custom0Pick your own checks
GET
/profiles/checks

List all available verification checks with their ID, label, description, and level (required / optional).

POST
/profiles/create

Create a trust profile. Returns a YAML file.

FieldTypeDescription
template string newsroom, insurance, creator, ai-labelling, or custom
name string Human-readable profile name
issuer string Organization or person issuing the profile
checks string Comma-separated check IDs (overrides template)
curl
curl -X POST https://16.61.203.65/rest/profiles/create \
  -F "template=newsroom" \
  -F "name=Wire Photo Policy" \
  -o profile.yml

IPTC source types

GET
/iptc/source-types

List all IPTC digital source types. These slugs declare how an image was created and are used with the digital_source_type parameter on embed endpoints.

SlugLabelAI
trainedAlgorithmicMedia Created using Generative AI yes
compositeWithTrainedAlgorithmicMedia Edited using Generative AI yes
digitalCapture Digital capture from real life no
humanEdits Human-edited media no
screenCapture Screen capture no

Showing a subset. Call the endpoint for the full list of 17 source types.

Error handling

All errors return JSON with a detail field.

StatusMeaningExample
400 Bad request Invalid JSON, bad YAML, unknown source type
404 Not found No metadata in the image
422 Validation error Missing required form field
{ "detail": "No JPEG Trust metadata found." }

Health check

GET
/health

Returns {"status": "ok"} when the API is running. Use this for uptime monitoring.