Endpoints
Two endpoints cover the API workflow. Both accept a multipart form with a single image field (JPEG, PNG, or WebP, up to 25 MB) and answer JSON. Authentication is the bearer key.
Add the opt-out signal
Section titled “Add the opt-out signal”POST /api/v1/protectEmbeds the machine-readable opt-out signal in the file metadata. Optional Dashboard layers are intentionally not guessed by the API’s default endpoint. Each successful call counts one image against your allowance; failed transforms are refunded and do not count.
Request
Section titled “Request”| Field | Type | Notes |
|---|---|---|
image |
file (multipart) | Required. image/* content type, up to 25 MB. |
curl -X POST https://api.noaishield.com/api/v1/protect \ -H "Authorization: Bearer $NOAI_API_KEY" \ -o response.json// JavaScript (Node 18+)import { readFile, writeFile } from "node:fs/promises";
const bytes = await readFile("artwork.png");const form = new FormData();form.set("image", new Blob([bytes], { type: "image/png" }), "artwork.png");
const res = await fetch("https://api.noaishield.com/api/v1/protect", { method: "POST", headers: { authorization: `Bearer ${process.env.NOAI_API_KEY}` }, body: form,});if (!res.ok) throw new Error((await res.json()).error);
const data = await res.json();await writeFile(data.filename, Buffer.from(data.imageBase64, "base64"));# Python (requests)import base64, os, requests
with open("artwork.png", "rb") as f: res = requests.post( "https://api.noaishield.com/api/v1/protect", headers={"Authorization": f"Bearer {os.environ['NOAI_API_KEY']}"}, files={"image": ("artwork.png", f, "image/png")}, )res.raise_for_status()data = res.json()
with open(data["filename"], "wb") as out: out.write(base64.b64decode(data["imageBase64"]))Response
Section titled “Response”{ "imageBase64": "...", "mimeType": "image/png", "filename": "noai-shield-marked.png", "sha256": "...", "signals": ["iptc.dataMining"], "creditsRemaining": 42}| Field | Description |
|---|---|
imageBase64 |
The marked image, base64-encoded. Decode it and save it as your published copy. |
mimeType |
Media type of the produced bytes. Re-encoding can change it (for example WebP in, PNG out). |
filename |
Suggested file name, extension matching the produced bytes. |
sha256 |
SHA-256 of the marked bytes. This API call does not create a PDF or hosted record. |
signals |
The machine-readable opt-out signals written, e.g. iptc.dataMining. |
creditsRemaining |
Image credits left after this successful marking call. |
The produced format can differ from the upload. Always name and serve the file from the response fields, never from the input’s extension.
Verify an image
Section titled “Verify an image”POST /api/v1/verifyChecks the opt-out signal, NoAI Shield service-signature metadata, and the experimental pixel fingerprint. Free, and uses the same verification core as the dashboard.
Request
Section titled “Request”| Field | Type | Notes |
|---|---|---|
image |
file (multipart) | Required. image/* content type, up to 25 MB. |
curl -X POST https://api.noaishield.com/api/v1/verify \ -H "Authorization: Bearer $NOAI_API_KEY" \// JavaScript (Node 18+)import { readFile } from "node:fs/promises";
const bytes = await readFile("artwork.png");const form = new FormData();form.set("image", new Blob([bytes], { type: "image/png" }), "artwork.png");
const res = await fetch("https://api.noaishield.com/api/v1/verify", { method: "POST", headers: { authorization: `Bearer ${process.env.NOAI_API_KEY}` }, body: form,});const { optedOut } = await res.json();# Python (requests)import os, requests
with open("artwork.png", "rb") as f: res = requests.post( "https://api.noaishield.com/api/v1/verify", headers={"Authorization": f"Bearer {os.environ['NOAI_API_KEY']}"}, files={"image": ("artwork.png", f, "image/png")}, )print(res.json()["optedOut"])Response
Section titled “Response”{ "optedOut": true, "signals": ["iptc.dataMining"], "provenance": { "present": false, "valid": false, "verifiable": true }, "fingerprint": { "present": false, "confidence": 0.51, "blocks": 4096 }, "sha256": "..."}| Field | Description |
|---|---|
optedOut |
true when the image carries the standardized IPTC/PLUS opt-out field. |
signals |
The signals found, empty when the field is absent. |
provenance |
Whether a NoAI Shield service-signature tag is present, whether this server can verify it, and whether it is valid. |
fingerprint |
Statistical result from our experimental in-pixel detector. confidence is a match ratio, not a guarantee of authorship. |
sha256 |
SHA-256 of the uploaded bytes, for matching against a dated NoAI Shield record. |
A common pattern: check, then mark
Section titled “A common pattern: check, then mark”Checking is free, so pipelines can check first and add the field only when it is absent:
const verdict = await callApi("/api/v1/verify", bytes);if (!verdict.optedOut) { const done = await callApi("/api/v1/protect", bytes); await save(done);}This pattern is useful for pipelines that want to avoid marking an already-marked file. The repository pull-request flow checks first; individual clients may choose to mark directly.