Integrate TrustAnchor into your publishing workflow. Anchor photos, videos, and documents at the moment of publication — giving your audience a permanent way to verify authenticity.
Pass your API key via the X-API-Key header:
X-API-Key: ta_sk_your_api_key_here
Alternatively, use Authorization: Bearer ta_sk_.... Keys start with ta_sk_ to distinguish them from session tokens.
https://api.trustanchor.io
Upload and anchor a file. Computes SHA-256 hash, pins to IPFS, builds BCMR metadata, and returns a verification short code.
Content-Type: multipart/form-data
Permission: anchor
| file | Required. The file to anchor. |
| caption | Optional. Description (max 500 chars). |
{
"anchor_id": 142,
"short_code": "Ab3xYz",
"file_hash": "e3b0c44298fc1c149afbf4c8996fb924...",
"file_name": "press-release.jpg",
"file_type": "image/jpeg",
"file_size": 245760,
"ipfs_cid": "QmYwAPJzv5CZsnA625s3Xf2nem...",
"ipfs_url": "https://gateway.pinata.cloud/ipfs/QmYw...",
"bcmr_cid": "QmRbcH8gTk2n4fVp...",
"status": "uploaded",
"verify_url": "https://trustanchor.io/verify?code=Ab3xYz",
"badge_svg": "https://api.trustanchor.io/badge/Ab3xYz.svg",
"badge_embed": "<a href=...><img src=... /></a>",
"c2pa": false
}
Check if a file hash, token category ID, or short code is anchored. API key optional.
{
"found": true,
"anchors": [
{
"id": 142,
"file_hash_sha256": "e3b0c44298fc1c149afbf4c8...",
"file_name": "press-release.jpg",
"short_code": "Ab3xYz",
"status": "uploaded",
"created_at": "2026-06-06 14:30:00",
"handle": "reuters"
}
]
}
Get details of a specific anchor. Scoped to your own anchors only.
Permission: anchor
Returns an embeddable SVG verification badge for an anchor. Also available as .png. No authentication required.
Register a webhook URL to receive notifications when anchors are created or confirmed on-chain.
Permission: webhook
| url | Required. HTTPS URL to receive POST callbacks. |
| events | Optional. Array: ["anchor.created", "anchor.confirmed"] |
List all your registered webhooks.
Delete a webhook.
Every anchor gets an embeddable badge that you can place on your website to show verification status.
The badge URL is returned in the POST /v1/anchor response.
Formats: .svg (recommended) or .png
<!-- Embed in your HTML -->
<a href="https://trustanchor.io/verify?code=Ab3xYz">
<img src="https://api.trustanchor.io/badge/Ab3xYz.svg"
alt="Trust Anchored" />
</a>
The badge_embed field in the anchor response contains a ready-to-paste HTML snippet.
TrustAnchor computes a perceptual hash (dHash) for every image that is anchored. This allows verification even when an image has been re-compressed, resized, cropped, or screenshotted.
When verifying via the website's Upload File tab, images are automatically checked for both
exact SHA-256 matches and visual similarity. The API GET /v1/verify/{hash} endpoint
performs exact matching. For perceptual matching via API, compute the file's SHA-256 hash and check
for exact matches first — perceptual image upload matching is coming to the API soon.
How it works: Each image is resized to a tiny 9×8 grayscale thumbnail, and adjacent pixel brightness differences produce a 64-bit fingerprint. Two images with a Hamming distance under 10 bits (>84% similar) are considered a visual match.
Each API key has default limits of 30 requests/minute and 1,000 requests/day. Rate limit info is returned in response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
When limits are exceeded, the API returns 429 Too Many Requests with a Retry-After header.
Webhook payloads are signed with HMAC-SHA256 using the secret returned when you create the webhook. Verify the signature to ensure the payload is authentic:
X-TrustAnchor-Signature: sha256=<hmac_hex>
X-TrustAnchor-Event: anchor.created
Content-Type: application/json
Events: anchor.created, anchor.confirmed, anchor.failed, or * for all.
Webhooks are disabled after 10 consecutive delivery failures.
cURL
# Anchor a file
curl -X POST https://api.trustanchor.io/v1/anchor \
-H "X-API-Key: ta_sk_your_key_here" \
-F "file=@photo.jpg" \
-F "caption=Breaking news photo from city hall"
# Verify a hash
curl https://api.trustanchor.io/v1/verify/e3b0c44298fc1c149afbf4c8996fb924... \
-H "X-API-Key: ta_sk_your_key_here"
Python
import requests
API_KEY = "ta_sk_your_key_here"
BASE = "https://api.trustanchor.io"
# Anchor a file
with open("photo.jpg", "rb") as f:
r = requests.post(f"{BASE}/v1/anchor",
headers={"X-API-Key": API_KEY},
files={"file": f},
data={"caption": "Press photo"})
print(r.json()["verify_url"])
# Verify a hash
r = requests.get(f"{BASE}/v1/verify/{file_hash}",
headers={"X-API-Key": API_KEY})
print(r.json()["found"])
Node.js
const fs = require('fs');
const API_KEY = 'ta_sk_your_key_here';
const BASE = 'https://api.trustanchor.io';
// Anchor a file
const form = new FormData();
form.append('file', fs.createReadStream('photo.jpg'));
form.append('caption', 'Press photo');
const res = await fetch(`${BASE}/v1/anchor`, {
method: 'POST',
headers: { 'X-API-Key': API_KEY },
body: form,
});
const data = await res.json();
console.log(data.verify_url);
All errors return JSON with an error field:
{ "error": "Monthly anchor limit reached (7). Upgrade your plan for more." }
| 400 | Bad request (invalid input) |
| 401 | Missing or invalid API key |
| 403 | API key lacks required permission |
| 409 | File already anchored |
| 413 | File exceeds plan size limit |
| 422 | Validation error |
| 429 | Rate limit exceeded |
The Publisher API uses simple, usage-based pricing. No subscription required — you only pay for what you use.
| Anchors/month | Price per anchor | Example cost |
| First 100 | Free | $0.00 |
| 101 – 1,000 | $0.02 | 900 anchors = $18.00 |
| 1,001 – 10,000 | $0.01 | 9,000 anchors = $90.00 |
| 10,001+ | $0.005 | Scales with volume |
Charges are calculated at the end of each month and billed via Stripe. You can monitor your usage in real time on the Settings page. Need custom volume pricing? Contact us.