CMS Integration Guide
Integrate Verimago signing into your newsroom's publish pipeline. Every video your team publishes gets a cryptographic certificate automatically.
Architecture
Editor uploads video → CMS stores file → Webhook computes SHA-256 hash
→ POST /v1/sign with hash + metadata → Store verifyUrl → Render shield in article
Your video file never leaves your infrastructure. Only the SHA-256 hash is sent to Verimago.
Step 1: Get your API key
See Publisher Quick Start — Step 1. You need a persistent API key (starts with veri_live_).
Step 2: Hash the video on your server
Node.js
const crypto = require('crypto');
const fs = require('fs');
function hashFile(filePath) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256');
const stream = fs.createReadStream(filePath);
stream.on('data', (chunk) => hash.update(chunk));
stream.on('end', () => resolve('sha256:' + hash.digest('hex')));
stream.on('error', reject);
});
}
Python
import hashlib
def hash_file(path):
sha = hashlib.sha256()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(8192), b''):
sha.update(chunk)
return f'sha256:{sha.hexdigest()}'
Shell
echo "sha256:$(shasum -a 256 video.mp4 | cut -d' ' -f1)"
Step 3: Sign via API
const response = await fetch('https://api.verimago.io/v1/sign', {
method: 'POST',
headers: {
'Authorization': Bearer ${VERIMAGO_API_KEY},
'Content-Type': 'application/json',
},
body: JSON.stringify({
contentHash: hash, // sha256:abc123...
headline: article.title, // from your CMS
journalist: article.author, // from your CMS
location: article.dateline, // optional
recordedAt: video.capturedAt, // optional
contentType: 'AUTHENTIC', // or AI_ENHANCED, AI_GENERATED
captureMode: 'VIDEO', // or PHOTO
}),
});
const { verifyUrl, shieldState, signedAt } = await response.json();
Step 4: Store the certificate reference
Add these fields to your video/article model:
ALTER TABLE videos ADD COLUMN verimago_verify_url TEXT;
ALTER TABLE videos ADD COLUMN verimago_shield TEXT;
ALTER TABLE videos ADD COLUMN verimago_signed_at TIMESTAMPTZ;
Store the verifyUrl, shieldState, and signedAt returned from the sign endpoint.
Step 5: Render the shield
In your article template, render the verification badge:
<div class="verimago-badge">
<a href="{{ video.verimago_verify_url }}" target="_blank" rel="noopener">
<img src="https://verimago.io/badge/{{ video.verimago_shield | lower }}.svg"
alt="Verified by Verimago" width="120" />
</a>
</div>
Platform-specific examples
WordPress
Add to your theme's functions.php or as a plugin:
add_action('add_attachment', function($post_id) {
$file = get_attached_file($post_id);
$mime = get_post_mime_type($post_id);
if (strpos($mime, 'video/') !== 0) return;
$hash = 'sha256:' . hash_file('sha256', $file);
$response = wp_remote_post('https://api.verimago.io/v1/sign', [
'headers' => [
'Authorization' => 'Bearer ' . VERIMAGO_API_KEY,
'Content-Type' => 'application/json',
],
'body' => json_encode([
'contentHash' => $hash,
'headline' => get_the_title($post_id),
'contentType' => 'AUTHENTIC',
'captureMode' => 'VIDEO',
]),
]);
if (!is_wp_error($response)) {
$body = json_decode(wp_remote_retrieve_body($response), true);
update_post_meta($post_id, '_verimago_verify_url', $body['verifyUrl']);
update_post_meta($post_id, '_verimago_shield', $body['shieldState']);
}
});
Arc XP / Custom CMS
Add a post-publish webhook:
// webhook handler: POST /hooks/verimago-sign
app.post('/hooks/verimago-sign', async (req, res) => {
const { videoUrl, articleId, title, author } = req.body;
// Download video and compute hash
const hash = await hashFromUrl(videoUrl);
// Sign with Verimago
const cert = await signWithVerimago(hash, { headline: title, journalist: author });
// Update article record
await db.articles.update(articleId, {
verimagoVerifyUrl: cert.verifyUrl,
verimagoShield: cert.shieldState,
});
res.json({ ok: true });
});
Batch signing
For archives or bulk uploads, use a script:
#!/bin/bash
API_KEY="veri_live_your_key_here"
for file in videos/*.mp4; do
HASH="sha256:$(shasum -a 256 "$file" | cut -d' ' -f1)"
TITLE=$(basename "$file" .mp4)
curl -s -X POST https://api.verimago.io/v1/sign \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{\"contentHash\": \"$HASH\", \"headline\": \"$TITLE\", \"contentType\": \"AUTHENTIC\", \"captureMode\": \"VIDEO\"}" \
| jq '.verifyUrl'
sleep 0.5 # respect rate limits
done
Error handling
| Error | Cause | Fix |
|---|---|---|
| 401 Unauthorized | Invalid or expired API key | Regenerate key at Settings → API Keys |
| 400 "contentHash must start with sha256:" | Missing sha256: prefix | Prepend sha256: to your hex hash |
| 400 "contentType must be..." | Invalid content type | Use AUTHENTIC, AI_ENHANCED, or AI_GENERATED |
| 409 Conflict (hash already signed) | This file was already signed | The response includes the existing certificate details |
| 429 Too Many Requests | Rate limit exceeded | Implement exponential backoff or reduce batch rate |
Testing
Use the staging environment for development:
Base URL: https://staging-api.verimago.io
Staging uses software keys (not HSM) and a separate database. Certificates created on staging are not publicly verifiable.