API

Content provenance for production systems

Sign, stream, and verify with C2PA

Start with eleven core operations. Open the management, advanced, or program reference only when your integration needs it.

Start here

Choose the shortest path to signed output

1

Create an API key

Create a key in the dashboard. Signing requires the key. Public verification does not.

2

Sign and verify

Use POST /sign for text, POST /sign/media for one file or a composition with many ingredients, and POST /sign/rich for a mixed article.

3

Stream or wrap OpenAI

Sign completed text over SSE, mark incremental segments, or call the OpenAI-compatible signing proxy.

Quickstart

First signed document in 60 seconds

Sign plain text, then pass the returned signed_text to the unauthenticated verifier.

export ENCYPHER_API_KEY="<your-api-key>"

SIGNED=$(curl -sS https://api.encypher.com/api/v1/sign \
  -H "Authorization: Bearer $ENCYPHER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text":"This document carries portable provenance.","document_title":"First signed document"}')

curl -sS https://api.encypher.com/api/v1/public/verify \
  -H "Content-Type: application/json" \
  -d "$(printf '%s' "$SIGNED" | jq '{text:.data.document.signed_text}')"

Store signed_text exactly as returned. Normalizing or retyping it can remove the invisible provenance payload.

Multi-ingredient media

Sign one MP4 with 10-20 source ingredients

Send the finished composition once as file. Repeat the multipart ingredients field for every source clip, image, or audio file. Each source becomes a separate c2pa.ingredient.v3 assertion in the final Content Credential.

curl -X POST https://api.encypher.com/api/v1/sign/media   -H "Authorization: Bearer $ENCYPHER_API_KEY"   -H "Idempotency-Key: campaign-cut-001"   -F "[email protected];type=video/mp4"   -F "title=Campaign cut"   -F "[email protected];type=video/mp4"   -F "[email protected];type=video/mp4"   -F "[email protected];type=image/png"

ingredients means components

Repeat this field. Order is preserved. Every file gets relationship componentOf, and its filename becomes the ingredient title. Do not send an array, comma-separated list, or ZIP archive.

ingredient means one parent

The singular field is only for one edited predecessor with relationship parentOf. It is not the way to send composition sources.

Signed and unsigned sources

A signed source keeps its existing C2PA provenance chain. An unsigned source is still recorded, with unknown prior provenance rather than invented history.

The composition contract accepts up to 50 effective ingredients, and a parent counts toward the 50. The public limit is the whole multipart request body -- target, every ingredient, text fields, and multipart framing together -- at or below 100,000,000 bytes (100 MB). Cloudflare measures a 100 MiB edge ceiling in front of the API, and this application cap sits deliberately below it so an over-limit request earns a JSON 413 rather than an edge rejection. Check data.ingredient_count in the response. A mismatch means the final credential does not describe the composition you intended.

For a supported asset or composition at or above 100 MB, call GET /sign/media/hash/capabilities first and use the POST /sign/media/prepare and POST /sign/media/finalize local-hash workflow only when the response reports enabled: true for your organization. The capabilities response, not a static size claim on this page, is authoritative. Prepared mode keeps media payload bytes local and accepts ordered parent and component ingredient descriptors, AI-output ancestry, preserve_source_rights, and use_rights_profile. Ingredient descriptors contain only bounded container structure, size, MIME type, relationship, title, and a SHA-256 digest.

A request rejected above Cloudflare's 100 MiB edge ceiling is answered by the edge, not this API: that response may be HTML and lack Encypher's error.code and correlation_id fields. Branch on the HTTP status and Content-Type before parsing JSON, and treat any 413 as a size failure even when the JSON envelope is absent.

Authentication

One Encypher key

Send your Encypher API key on authenticated operations:

Authorization: Bearer <your-api-key>

POST /public/verify and POST /public/verify/media require no key. The OpenAI proxy also requires X-OpenAI-API-Key. Encypher forwards that key for the request and does not persist it.

Errors and limits

Handle the envelope, not the prose

{
  "success": false,
  "error": {
    "code": "E_RATE_SIGN",
    "message": "Signing rate limit exceeded"
  },
  "correlation_id": "req-abc123"
}

Branch on error.code. Log correlation_id and the X-Request-ID response header. On 429, honor Retry-After. Rich signing accepts up to 20 images at 10 MB each, 10 audio files at 50 MB each, and 5 video files at 100 MB each.

State and retries

Persist the identifiers returned by the API

document_id
Use for document lookup, status, history, revocation, and support.
run_id
Use to resume or inspect whole-document SSE signing progress.
session_id
Reuse across incremental start, segment, finalize, and status calls.
correlation_id
Log it with failures so support can trace the request.

API reference

Core API

Eleven operations for signing, verification, streaming, and OpenAI-compatible generation. Use the reference filter to search this surface.