Integrate Audiverify certificate creation, verification, claims management, and webhooks into your platform. API access is included with every account.
https://audiverify.com/api/v1All requests require an API key. API access is included with every account. You can generate keys from the API Keys page in your dashboard, or contact info@motivagroove.com for help. Keys are prefixed with mot_.
Pass your key via either method:
X-API-Key header
curl -H "X-API-Key: mot_your_key_here" \
https://audiverify.com/api/v1/certificatesBearer token
curl -H "Authorization: Bearer mot_your_key_here" \
https://audiverify.com/api/v1/certificatesEach API key is issued with specific scopes that control access. Keys are assigned scopes during onboarding -- you cannot change them yourself.
certificates:readList and retrieve certificate details
certificates:writeCreate new certificates via the API
claims:readView claims and dispute status
claims:writeFile and manage claims
verify:readVerify certificates by number, ISRC, or SHA-256
webhooks:readList registered webhook endpoints
webhooks:manageCreate, update, rotate secrets, and delete webhooks
Insufficient scope returns 403 with the required scope in the error body.
API keys are rate-limited per minute. Default limit is 100 requests/minute. Exceeding the limit returns 429 Too Many Requests.
Every API response includes an X-Request-Id header (e.g. req_a1b2c3d4...). Include this ID in any support request for fast debugging.
For POST and PUT requests, you can pass an Idempotency-Key header to ensure the same operation is not executed twice. Cached responses are replayed for 24 hours and include an Idempotency-Replayed: true header.
Idempotent request
curl -X POST https://audiverify.com/api/v1/certificates \
-H "X-API-Key: mot_your_key" \
-H "Idempotency-Key: unique-request-id-123" \
-H "Content-Type: application/json" \
-d '{"track_title":"My Song","artist_name":"Artist","sha256_fingerprint":"a1b2c3..."}'Cursor pagination: For large result sets, use cursor instead of offset. The response includes a next_cursor value when more results are available.
400bad_requestMissing or invalid parameters401unauthorizedInvalid or missing API key402payment_requiredInsufficient credits403forbiddenInsufficient permissions404not_foundResource not found409duplicateCertificate with this fingerprint already exists429rate_limitedRate limit exceeded500internal_errorServer errorError response format
{
"error": "Missing required fields: track_title, artist_name, sha256_fingerprint",
"code": "bad_request"
}402 - Includes credits remaining and purchase link
{
"error": "Insufficient credits",
"code": "payment_required",
"credits_remaining": 0,
"purchase_url": "https://audiverify.com/dashboard/billing",
"docs": "https://audiverify.com/docs#credits"
}409 - Includes existing certificate details
{
"error": "A certificate with this audio fingerprint already exists",
"code": "duplicate",
"existing_certificate_number": "MOT-2026-XXXXXXX",
"existing_certificate_id": "uuid",
"verification_url": "https://audiverify.com/verify/MOT-2026-XXXXXXX"
}/api/v1/certificatescertificates:readQuery Parameters
limitnumberMax results (default 20, max 100)offsetnumberPagination offsetstatusstringFilter: active, revokedartiststringFilter by artist name (partial match)Response
{
"certificates": [
{
"id": "uuid",
"certificate_number": "MOT-2026-O8RZNDOO",
"track_title": "c",
"artist_name": "sasa radic",
"status": "active",
"isrc": "GXHE72600042",
"sha256_fingerprint": "e3b0c44...",
"issued_at": "2026-02-13T14:32:00Z",
"verification_url": "https://audiverify.com/verify/MOT-2026-O8RZNDOO"
}
],
"pagination": {
"total": 12,
"limit": 20,
"offset": 0,
"has_more": false
}
}/api/v1/certificatescertificates:writeRequest Body (JSON)
track_titlestringrequiredTitle of the trackartist_namestringrequiredName of the artistsha256_fingerprintstringrequired64-char hex SHA-256 hash of the audio fileisrcstringISRC code (auto-uppercased)typestringsound_recording or composition (default: sound_recording)declaration_textstringDeclaration type (default: Original Work)audio_file_namestringOriginal filename of the audioResponse
{
"success": true,
"certificate": {
"id": "uuid",
"certificate_number": "MOT-2026-XXXXXXX",
"track_title": "My Song",
"artist_name": "Artist Name",
"status": "active",
"sha256_fingerprint": "a1b2c3d4...",
"issued_at": "2026-02-15T10:00:00Z",
"verification_url": "https://audiverify.com/verify/MOT-2026-XXXXXXX"
}
}/api/v1/verifyverify:readQuery Parameters
certificate_numberstringe.g. MOT-2026-O8RZNDOOsha256string64-char hex SHA-256 hashisrcstringISRC codeResponse
{
"verified": true,
"certificate": {
"certificate_number": "MOT-2026-O8RZNDOO",
"track_title": "c",
"artist_name": "sasa radic",
"status": "active",
"isrc": "GXHE72600042",
"sha256_fingerprint": "e3b0c44...",
"declaration": "Original Work"
},
"verification_url": "https://audiverify.com/verify/MOT-2026-O8RZNDOO"
}/api/v1/verifyverify:readRequest Body (JSON)
sha256stringrequired64-char hex SHA-256 hash of the audio fileResponse
{
"verified": false,
"message": "No matching certificate found for this hash",
"sha256": "abc123..."
}/api/v1/verify/deepverify:readQuery Parameters
certificate_numberstringe.g. MOT-2026-XXXXXXXsha256string64-char hex SHA-256 hashisrcstringISRC codeResponse
{
"verified": true,
"certificate": { ... },
"ai_disclosure": {
"involvement": "assisted",
"tools": ["Suno"],
"plan_tier": "paid"
},
"deep_scan": {
"dwd_status": "clean",
"ai_detection_status": "not_detected"
},
"contributors": [...],
"version_history": [...],
"credits_remaining": 42
}/api/v1/billing/checkoutbilling:writeResponse
{
"current_tier": "free",
"monthly_requests_used": 450,
"monthly_requests_limit": 10000,
"available_tiers": {
"free": { "price": "$0/month", "requests": "10,000/month" },
"starter": { "price": "$49/month", "requests": "50,000/month" },
"pro": { "price": "$199/month", "requests": "500,000/month" }
}
}/api/v1/billing/checkoutbilling:writeRequest Body (JSON)
tierstringrequired"starter" or "pro"success_urlstringCustom redirect after paymentResponse
{
"checkout_url": "https://checkout.stripe.com/...",
"session_id": "cs_...",
"tier": "starter",
"price": "$49.00/month"
}/api/v1/claimsclaims:readQuery Parameters
limitnumberMax results (default 20, max 100)offsetnumberPagination offsetstatusstringFilter: pending, responded, resolved, expiredResponse
{
"claims": [
{
"id": "uuid",
"type": "ownership",
"status": "pending",
"description": "I am the original author...",
"claimant": {
"name": "Jane Doe",
"email": "jane@example.com"
},
"certificate": {
"certificate_number": "MOT-2026-O8RZNDOO",
"track_title": "c",
"artist_name": "sasa radic"
},
"response_deadline": "2026-03-15T00:00:00Z",
"created_at": "2026-02-15T10:00:00Z"
}
],
"pagination": { "total": 1, "limit": 20, "offset": 0, "has_more": false }
}/api/v1/webhookswebhooks:readResponse
{
"webhooks": [
{
"id": "uuid",
"url": "https://yourapp.com/hooks/audiverify",
"events": ["certificate.created", "claim.filed"],
"is_active": true,
"stats": {
"success_count": 42,
"failure_count": 1
}
}
],
"available_events": [
"certificate.created", "certificate.updated", "certificate.revoked",
"claim.filed", "claim.responded", "claim.resolved",
"contributor.invited", "contributor.acknowledged",
"payment.completed", "credits.purchased", "credits.used"
]
}/api/v1/webhookswebhooks:manageRequest Body (JSON)
urlstringrequiredHTTPS endpoint to receive webhook eventseventsstring[]Events to subscribe to (default: certificate.created)descriptionstringHuman-readable label for this webhookResponse
{
"success": true,
"webhook": {
"id": "uuid",
"url": "https://yourapp.com/hooks/audiverify",
"events": ["certificate.created"],
"secret": "abc123...",
"created_at": "2026-02-15T10:00:00Z"
},
"message": "Webhook created. Save the secret - it will not be shown again."
}/api/v1/webhookswebhooks:manageQuery Parameters
idstringrequiredUUID of the webhook to deleteResponse
{
"success": true,
"message": "Webhook deleted"
}/api/v1/webhookswebhooks:manageQuery Parameters
idstringrequiredUUID of the webhook (query param)rotate_secretbooleanGenerate a new HMAC secret (old secret stops working immediately)urlstringNew HTTPS endpoint URLis_activebooleanEnable or disable the webhook (resets failure count when re-enabling)eventsstring[]Updated list of event types to subscribe toResponse
{
"success": true,
"message": "Webhook updated",
"updated_fields": ["rotate_secret", "is_active"],
"new_secret": "avwhsec_abc123...",
"warning": "Save this secret now. It will not be shown again."
}Every webhook delivery sends a JSON body with a consistent structure. All timestamps are ISO 8601 UTC.
All events
{
"event": "certificate.created",
"timestamp": "2026-02-15T14:32:00.000Z",
"data": {
// event-specific fields
}
}certificate.created
{
"event": "certificate.created",
"timestamp": "2026-02-15T14:32:00.000Z",
"data": {
"certificate_id": "550e8400-e29b-41d4-a716-446655440000",
"certificate_number": "MOT-2026-O8RZNDOO",
"track_title": "Crystal Rain",
"artist_name": "Sasa Radic",
"status": "active",
"isrc": "GXHE72600042",
"sha256_fingerprint": "a7f3d1b2c9e84f6a0b5d2e7c3f8a1d4b...",
"verification_url": "https://audiverify.com/verify/MOT-2026-O8RZNDOO"
}
}claim.filed
{
"event": "claim.filed",
"timestamp": "2026-02-15T14:32:00.000Z",
"data": {
"claim_id": "550e8400-e29b-41d4-a716-446655440001",
"claim_type": "ownership",
"status": "pending",
"certificate_number": "MOT-2026-O8RZNDOO",
"claimant_name": "Jane Doe"
}
}contributor.invited
{
"event": "contributor.invited",
"timestamp": "2026-02-15T14:32:00.000Z",
"data": {
"contributor_id": "550e8400-e29b-41d4-a716-446655440002",
"contributor_name": "John Producer",
"role": "Producer",
"certificate_number": "MOT-2026-O8RZNDOO",
"status": "pending"
}
}credits.purchased
{
"event": "credits.purchased",
"timestamp": "2026-02-15T14:32:00.000Z",
"data": {
"amount": 100,
"price_paid": "29.00",
"currency": "GBP",
"payment_id": "pi_3abc123..."
}
}Content-Typeapplication/jsonX-Audiverify-Signaturesha256=<hex-signature>X-Audiverify-Eventcertificate.createdX-Audiverify-Delivery<webhook-id>X-Audiverify-Timestamp<ISO-8601 timestamp>User-AgentAudiverify-Webhooks/1.0Every webhook delivery is signed using HMAC-SHA256 with the secret returned when you created the webhook. Always verify the signature before processing the payload.
How it works:
HMAC-SHA256(webhook_secret, raw_body)X-Audiverify-Signature: sha256=<hex>Node.js verification
import crypto from 'crypto';
function verifyAudiverify(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
const received = signatureHeader.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex')
);
}
// In your Express/Next.js handler:
app.post('/hooks/audiverify', (req, res) => {
const sig = req.headers['x-audiverify-signature'];
if (!verifyAudiverify(req.body, sig, process.env.AUDIVERIFY_WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = JSON.parse(req.body);
console.log('Received:', event, data);
res.status(200).send('OK');
});Python verification
import hmac, hashlib, json
def verify_audiverify(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
received = signature_header.replace("sha256=", "")
return hmac.compare_digest(expected, received)
# In your Flask/FastAPI handler:
@app.post("/hooks/audiverify")
async def webhook(request: Request):
body = await request.body()
sig = request.headers.get("x-audiverify-signature", "")
if not verify_audiverify(body, sig, os.environ["AUDIVERIFY_WEBHOOK_SECRET"]):
return JSONResponse(status_code=401, content={"error": "Invalid signature"})
payload = json.loads(body)
print(f"Received: {payload['event']}")
return {"ok": True}Security note
Always use timing-safe comparison (crypto.timingSafeEqual / hmac.compare_digest) to prevent timing attacks. Never use === or == for signature comparison.
Create your first certificate in 3 API calls:
1. Generate the SHA-256 fingerprint of your audio file
bash
sha256sum my-song.wav
# a7f3d1b2c9e84f6a0b5d2e7c3f8a1d4b...2. Create the certificate
bash
curl -X POST https://audiverify.com/api/v1/certificates \
-H "X-API-Key: mot_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"track_title": "My Song",
"artist_name": "My Name",
"sha256_fingerprint": "a7f3d1b2c9e84f6a0b5d2e7c3f8a1d4b..."
}'3. Verify it exists
bash
curl "https://audiverify.com/api/v1/verify?certificate_number=MOT-2026-XXXXXXX" \
-H "X-API-Key: mot_your_key_here"Copy-paste examples for common operations. Replace mot_your_key_here with your actual API key.
List certificates
const response = await fetch('https://audiverify.com/api/v1/certificates?limit=10', {
headers: { 'X-API-Key': process.env.MOTIVA_API_KEY }
});
const { certificates, pagination } = await response.json();
console.log(`Found ${pagination.total} certificates`);Create a certificate
import { createHash } from 'crypto';
import { readFileSync } from 'fs';
// 1. Hash the audio file
const audio = readFileSync('./my-song.wav');
const sha256 = createHash('sha256').update(audio).digest('hex');
// 2. Create the certificate
const res = await fetch('https://audiverify.com/api/v1/certificates', {
method: 'POST',
headers: {
'X-API-Key': process.env.MOTIVA_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
track_title: 'Crystal Rain',
artist_name: 'Sasa Radic',
sha256_fingerprint: sha256,
isrc: 'GXHE72600042',
type: 'sound_recording',
}),
});
const { certificate } = await res.json();
console.log('Certificate:', certificate.certificate_number);
console.log('Verify at:', certificate.verification_url);Verify a certificate
const res = await fetch(
'https://audiverify.com/api/v1/verify?certificate_number=MOT-2026-O8RZNDOO',
{ headers: { 'X-API-Key': process.env.MOTIVA_API_KEY } }
);
const data = await res.json();
if (data.verified) {
console.log('Verified:', data.certificate.track_title, 'by', data.certificate.artist_name);
} else {
console.log('Not found');
}Register a webhook
const res = await fetch('https://audiverify.com/api/v1/webhooks', {
method: 'POST',
headers: {
'X-API-Key': process.env.MOTIVA_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://yourapp.com/hooks/audiverify',
events: ['certificate.created', 'claim.filed', 'contributor.invited'],
description: 'Production webhook',
}),
});
const { webhook } = await res.json();
// Save this secret securely -- it is only shown once
console.log('Webhook secret:', webhook.secret);List certificates
import requests, os
headers = {"X-API-Key": os.environ["MOTIVA_API_KEY"]}
r = requests.get("https://audiverify.com/api/v1/certificates", headers=headers, params={"limit": 10})
data = r.json()
print(f"Found {data['pagination']['total']} certificates")Create a certificate
import hashlib, requests, os
# 1. Hash the audio file
with open("my-song.wav", "rb") as f:
sha256 = hashlib.sha256(f.read()).hexdigest()
# 2. Create the certificate
r = requests.post(
"https://audiverify.com/api/v1/certificates",
headers={
"X-API-Key": os.environ["MOTIVA_API_KEY"],
"Content-Type": "application/json",
},
json={
"track_title": "Crystal Rain",
"artist_name": "Sasa Radic",
"sha256_fingerprint": sha256,
"isrc": "GXHE72600042",
"type": "sound_recording",
},
)
cert = r.json()["certificate"]
print(f"Certificate: {cert['certificate_number']}")
print(f"Verify at: {cert['verification_url']}")Verify a certificate
import requests, os
r = requests.get(
"https://audiverify.com/api/v1/verify",
headers={"X-API-Key": os.environ["MOTIVA_API_KEY"]},
params={"certificate_number": "MOT-2026-O8RZNDOO"},
)
data = r.json()
if data["verified"]:
c = data["certificate"]
print(f"Verified: {c['track_title']} by {c['artist_name']}")
else:
print("Not found")List certificates
curl -s "https://audiverify.com/api/v1/certificates?limit=5" \
-H "X-API-Key: mot_your_key_here" | jq .Create a certificate
# Generate SHA-256 hash
SHA=$(sha256sum my-song.wav | cut -d' ' -f1)
curl -X POST "https://audiverify.com/api/v1/certificates" \
-H "X-API-Key: mot_your_key_here" \
-H "Content-Type: application/json" \
-d "{
\"track_title\": \"Crystal Rain\",
\"artist_name\": \"Sasa Radic\",
\"sha256_fingerprint\": \"$SHA\",
\"isrc\": \"GXHE72600042\"
}"Verify by ISRC
curl -s "https://audiverify.com/api/v1/verify?isrc=GXHE72600042" \
-H "X-API-Key: mot_your_key_here" | jq .verifiedDrop a verification widget directly into your website, distributor portal, or label dashboard. No API key required -- works with a single HTML snippet.
HTML
<!-- Add this where you want the widget to appear -->
<div
class="audiverify-verify"
data-certificate="MOT-2026-ABCDEF12"
data-theme="dark"
></div>
<!-- Add this before </body> -->
<script src="https://audiverify.com/embed.js" async></script>If you prefer full control, use an iframe directly:
HTML
<iframe
src="https://audiverify.com/embed/verify/MOT-2026-ABCDEF12?theme=dark"
width="100%"
height="340"
style="border:none;border-radius:8px"
title="Audiverify Certificate Verification"
loading="lazy"
></iframe>| Parameter | Default | Description |
|---|---|---|
data-certificate | required | The certificate number to verify |
data-theme | dark | "dark" or "light" -- matches your site's theme |
data-compact | false | Set to true for a minimal view (no contributors or fingerprint) |
data-hide-fingerprint | false | Set to true to hide the SHA-256 audio fingerprint |
data-width | 100% | CSS width value for the widget |
data-height | auto | CSS height -- auto picks 340px (or 160px in compact mode) |
Compact widget for sidebars
HTML
<div
class="audiverify-verify"
data-certificate="MOT-2026-ABCDEF12"
data-compact="true"
data-theme="dark"
></div>Light theme for light backgrounds
HTML
<div
class="audiverify-verify"
data-certificate="MOT-2026-ABCDEF12"
data-theme="light"
data-hide-fingerprint="true"
></div>Multiple certificates on one page
HTML
<div class="audiverify-verify" data-certificate="MOT-2026-AAAA1111"></div>
<div class="audiverify-verify" data-certificate="MOT-2026-BBBB2222"></div>
<div class="audiverify-verify" data-certificate="MOT-2026-CCCC3333"></div>
<script src="https://audiverify.com/embed.js" async></script>No API key required. The embed widget uses public verification data only. It does not expose any private data, audio files, or user information. The widget is sandboxed and cannot access the host page. Embed opens are tracked in the Audiverify analytics dashboard.
A machine-readable OpenAPI 3.1 spec is available for SDK generation, Postman import, or automated testing.
Fetch the spec
curl https://audiverify.com/api/v1/openapi.json | jq .Compatible with Swagger UI, Postman, Insomnia, and any OpenAPI 3.1 tooling.
Need help integrating? Contact info@motivagroove.com
API access is included with every account. Generate keys from your dashboard or email us for help getting started.
OpenAPI spec available at /api/v1/openapi.json for SDK generation and Postman import.