Developer docs
REST API FOR
AI PROVENANCE
ZorAI exposes a REST API that lets AI companies register generated content on Base Sepolia and returns metadata watermark fields they can embed into every file. Social platforms, newsrooms, and fact-checkers can then verify the same asset against the blockchain using either the content hash alone or the embedded watermark payload.
Integration flow
HOW PUBLISHERS SHOULD USE IT
The recommended flow keeps the blockchain record immutable while making the distributed file self-describing through metadata.
Generate the asset and compute a SHA-256 hash of the exact bytes you will publish.
Call POST /api/register with your API key and immutable storage pointer.
Embed the returned watermark and watermarkHash into EXIF or XMP metadata before delivery.
Let downstream platforms hash the file and call /api/verify to confirm provenance.
Authentication
API KEY MODEL
Registration is authenticated because it writes to the blockchain through your platform signer. Verification is public so downstream platforms can query provenance without a wallet or an API key.
x-api-key: YOUR_API_KEY
HTTP Status Codes
EXPECTED RESPONSES
All endpoints return JSON responses. Status codes indicate success or failure. Always check the status code before parsing the response body.
Success
Request succeeded (most common response)
Created
Resource created (registration successful)
Bad Request
Invalid parameters, missing fields, or malformed JSON
Unauthorized
Missing or invalid API key (POST /api/register only)
Too Many Requests
Rate limit exceeded. Retry after 60 seconds
Server Error
Internal server error. Check status page or retry later
Watermark
WHAT IS ACTUALLY VERIFIED
The blockchain-verifiable watermark includes only fields that can be reconstructed from on-chain state and the registration event. Optional publisher metadata can still be embedded, but only the watermark and watermarkHash are considered cryptographically verifiable.
{
"version": "1.0",
"zorai": true,
"imageHash": "8f9d...c1a2",
"model": "gpt-image-1",
"registeredAt": "2026-04-21T23:12:10.000Z",
"chain": "base-sepolia",
"chainId": 84532,
"contract": "0xd11eAEA00A92E6eE97DD14e6F97dbBb7971ef549",
"txHash": "0x8b2d...",
"blockNumber": 23812345
}Endpoints
REFERENCE
These endpoints are enough to register assets from an AI generation pipeline and verify them from moderation or newsroom tooling.
/api/registerRegister AI-generated content on ZorAI and receive a blockchain-backed watermark plus a metadata template you can embed before distribution.
Audience: AI providers
| Field | Type | Required | Description |
|---|---|---|---|
| imageHash | string | required | SHA-256 hash of the generated asset (hex string, 64 chars) |
| modelUsed | string | required | Model identifier such as "gpt-image-1" or "sdxl" |
| ipfsHash | string | required | IPFS CID or immutable storage pointer (recorded on-chain) |
| company | string | optional | Publisher name for metadata and on-chain record |
| externalId | string | optional | Your internal generation or asset tracking ID |
| sourceUrl | string | optional | Canonical URL where the asset will be served |
| contentType | string | optional | Asset type (defaults to "image") |
| riskLevel | number | optional | 0 = low, 1 = medium, 2 = high. Defaults to 0 |
| riskReasons | string[] | optional | Array of policy or moderation flags |
Example Request
curl -X POST https://zorai.vercel.app/api/register \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"imageHash": "8f9d2f1e...",
"modelUsed": "gpt-image-1",
"ipfsHash": "bafybeiexample...",
"company": "Example AI",
"externalId": "gen_12345",
"sourceUrl": "https://cdn.example.ai/assets/gen_12345.png",
"riskLevel": 0,
"riskReasons": []
}'Example Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"success": true,
"imageId": "8f9d2f1e...",
"txHash": "0x8b2d4f...",
"blockNumber": 23812345,
"chain": "base-sepolia",
"chainId": 84532,
"contract": "0xd11eAEA00A92E6eE97DD14e6F97dbBb7971ef549",
"watermark": {
"version": "1.0",
"zorai": true,
"imageHash": "8f9d2f1e...",
"model": "gpt-image-1",
"registeredAt": "2026-04-21T23:12:10.000Z",
"chain": "base-sepolia",
"chainId": 84532,
"contract": "0xd11eAEA00A92E6eE97DD14e6F97dbBb7971ef549",
"txHash": "0x8b2d4f...",
"blockNumber": 23812345
},
"watermarkHash": "eb02...",
"metadataTemplate": {
"aiGenerated": true,
"zorai": {
"watermark": { "version": "1.0", "zorai": true },
"watermarkHash": "eb02..."
},
"xmpFields": {
"XMP:ZorAI": "...full watermark...",
"XMP:ZorAIHash": "eb02...",
"XMP:AIGenerated": "true"
}
}
}/api/verify?id={imageHash}Look up an asset by SHA-256 hash and retrieve the blockchain registration record. Public endpoint, no API key required.
Audience: Social, news, fact-checkers
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | required | SHA-256 hash of the image or asset to check (hex string, 64 chars) |
Example Request
curl "https://zorai.vercel.app/api/verify?id=8f9d2f1e..."
Example Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"found": true,
"isAiGenerated": true,
"imageId": "8f9d2f1e...",
"ipfsHash": "bafybeiexample...",
"modelUsed": "gpt-image-1",
"creator": "0xAbC123...",
"registeredAt": "2026-04-21T23:12:10.000Z",
"isVerified": false,
"riskLevel": "low",
"riskReasons": [],
"watermark": {
"onChainHash": "eb02...",
"matchesBlockchain": null
}
}/api/verifyVerify a hash and optionally compare embedded ZorAI watermark metadata against the blockchain record. Public endpoint, no API key required.
Audience: Platforms with metadata
| Field | Type | Required | Description |
|---|---|---|---|
| imageHash | string | required | SHA-256 hash of the asset being inspected (hex string, 64 chars) |
| watermark | object | optional | Full watermark object extracted from file metadata. If provided, will be compared against blockchain. |
| watermarkHash | string | optional | Embedded watermark hash to compare (alternative to full watermark object) |
Example Request
curl -X POST https://zorai.vercel.app/api/verify \
-H "Content-Type: application/json" \
-d '{
"imageHash": "8f9d2f1e...",
"watermark": {
"version": "1.0",
"zorai": true,
"imageHash": "8f9d2f1e...",
"model": "gpt-image-1",
"registeredAt": "2026-04-21T23:12:10.000Z",
"chain": "base-sepolia",
"chainId": 84532,
"contract": "0xd11eAEA00A92E6eE97DD14e6F97dbBb7971ef549",
"txHash": "0x8b2d4f...",
"blockNumber": 23812345
}
}'Example Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"found": true,
"isAiGenerated": true,
"imageId": "8f9d2f1e...",
"watermark": {
"onChainHash": "eb02...",
"suppliedHash": "eb02...",
"matchesBlockchain": true
}
}Examples
CLIENT IMPLEMENTATIONS
You can consume the ZorAI REST API from any stack. Here are examples for a Python script, a FastAPI backend, and a verifier service.
Python
import hashlib
import json
import requests
BASE_URL = "https://zorai.vercel.app"
API_KEY = "your_api_key"
def sha256_file(path: str) -> str:
with open(path, "rb") as f:
return hashlib.sha256(f.read()).hexdigest()
image_hash = sha256_file("output.png")
try:
response = requests.post(
f"{BASE_URL}/api/register",
headers={
"Content-Type": "application/json",
"x-api-key": API_KEY,
},
json={
"imageHash": image_hash,
"modelUsed": "gpt-image-1",
"ipfsHash": "bafybeigdyrexample...",
"company": "Example AI",
"externalId": "gen_12345",
},
timeout=30,
)
response.raise_for_status()
payload = response.json()
print(f"Transaction: {payload['txHash']}")
print(json.dumps(payload["metadataTemplate"], indent=2))
except requests.exceptions.RequestException as e:
print(f"Error: {e}")FastAPI bridge
from fastapi import FastAPI, HTTPException
import hashlib
import requests
app = FastAPI()
ZORAI_BASE_URL = "https://zorai.vercel.app"
ZORAI_API_KEY = "your_api_key"
def sha256_bytes(content: bytes) -> str:
return hashlib.sha256(content).hexdigest()
@app.post("/publish-generated-image")
async def publish_generated_image(file_bytes: bytes):
image_hash = sha256_bytes(file_bytes)
try:
response = requests.post(
f"{ZORAI_BASE_URL}/api/register",
headers={
"Content-Type": "application/json",
"x-api-key": ZORAI_API_KEY,
},
json={
"imageHash": image_hash,
"modelUsed": "gpt-image-1",
"ipfsHash": "bafybeigdyrexample...",
"company": "Example AI",
},
timeout=30,
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise HTTPException(status_code=502, detail=str(e))Verifier service
async function verifyUpload(imageHash, extractedWatermark) {
const res = await fetch("https://zorai.vercel.app/api/verify", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
imageHash,
watermark: extractedWatermark,
}),
});
const result = await res.json();
return {
shouldLabelAsAI: result.found,
blockchainMatch: result.watermark.matchesBlockchain,
model: result.modelUsed,
riskLevel: result.riskLevel,
};
}Who benefits
TARGET USERS
The same infrastructure supports first-party publishers and third-party verification partners.
Write provenance to-chain and ship every generated asset with reusable metadata watermark fields.
Hash uploads, call /api/verify, and label content that maps to a ZorAI registration.
Validate suspicious images before publication and compare embedded metadata with the blockchain record.
Use the public endpoint to retrieve model, timestamp, risk level, and creator address.