shared.developerDocs
proofOfPlay.heroTitleproofOfPlay.heroTitleAccent
proofOfPlay.heroSubtitle
proofOfPlay.howItWorksTitle
proofOfPlay.howItWorksDesc
Step 1
proofOfPlay.steps.step1.title
proofOfPlay.steps.step1.desc
Step 2
proofOfPlay.steps.step2.title
proofOfPlay.steps.step2.desc
Step 3
proofOfPlay.steps.step3.title
proofOfPlay.steps.step3.desc
proofOfPlay.modelTitle
proofOfPlay.modelDesc
β
proofOfPlay.openVerification
proofOfPlay.openVerificationDesc
proofOfPlay.closedDiscovery
proofOfPlay.closedDiscoveryDesc
proofOfPlay.signatureTitle
proofOfPlay.signatureDesc
Signature payload format
v2.<timestamp>.<adId>.<impressionId>.<screenId>.<deviceId>| Field | Type | Description |
|---|---|---|
version | string | proofOfPlay.signatureFields.version |
timestamp | number | proofOfPlay.signatureFields.timestamp |
adId | string | proofOfPlay.signatureFields.adId |
impressionId | string | proofOfPlay.signatureFields.impressionId |
screenId | string | proofOfPlay.signatureFields.screenId |
deviceId | string | proofOfPlay.signatureFields.deviceId |
proofOfPlay.signatureSuffix
proofOfPlay.verificationTitle
proofOfPlay.nodeJs
verify-proof.js
const crypto = require('crypto');
// Fetch from /v1/advertiser/proof/.well-known/public-key
const PUBLIC_KEY_HEX = 'a5a9c43785680c62ebcd01ec49a0d6055fd140023df0f142c3e37c6abafce34f';
function verifyProof(proof) {
const payload = `v2.${proof.timestamp}.${proof.adId}.${proof.impressionId}.${proof.screenId}.${proof.deviceId}`;
const signatureHex = proof.signature.replace('ed25519=', '');
const signatureBytes = Buffer.from(signatureHex, 'hex');
const publicKey = crypto.createPublicKey({
key: Buffer.concat([
Buffer.from('302a300506032b6570032100', 'hex'),
Buffer.from(PUBLIC_KEY_HEX, 'hex')
]),
format: 'der',
type: 'spki'
});
return crypto.verify(null, Buffer.from(payload), publicKey, signatureBytes);
}
const proof = {
impressionId: '507f1f77bcf86cd799439011',
adId: 'campaign-abc123',
screenId: 'screen-xyz789',
deviceId: 'device-456',
timestamp: 1705401600000,
signature: 'ed25519=a1b2c3d4e5f6...'
};
console.log('Valid:', verifyProof(proof));proofOfPlay.python
verify_proof.py
from nacl.signing import VerifyKey
from nacl.exceptions import BadSignature
PUBLIC_KEY_HEX = 'a5a9c43785680c62ebcd01ec49a0d6055fd140023df0f142c3e37c6abafce34f'
def verify_proof(proof):
verify_key = VerifyKey(bytes.fromhex(PUBLIC_KEY_HEX))
payload = f"v2.{proof['timestamp']}.{proof['adId']}.{proof['impressionId']}.{proof['screenId']}.{proof['deviceId']}"
signature_hex = proof['signature'].replace('ed25519=', '')
signature_bytes = bytes.fromhex(signature_hex)
try:
verify_key.verify(payload.encode(), signature_bytes)
return True
except BadSignature:
return FalseproofOfPlay.curl
terminal
# Verify a proof using the API (no auth required)
curl -X POST https://api.trillboards.com/v1/advertiser/proof/verify-proof \
-H "Content-Type: application/json" \
-d '{
"signature": "ed25519=a1b2c3d4e5f6...",
"timestamp": 1705401600000,
"adId": "campaign-abc123",
"impressionId": "507f1f77bcf86cd799439011",
"screenId": "screen-xyz789",
"deviceId": "device-456"
}'
# Response:
# {
# "success": true,
# "verification": {
# "valid": true,
# "version": "v2"
# }
# }proofOfPlay.endpointsTitle
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v1/advertiser/proof/.well-known/public-key | ||
| POST | /v1/advertiser/proof/verify-proof | ||
| GET | /v1/advertiser/proof/proofs | ||
| GET | /v1/advertiser/proof/proofs/:id |
proofOfPlay.whyTitle
proofOfPlay.whyCards.tamperProof.title
proofOfPlay.whyCards.tamperProof.desc
proofOfPlay.whyCards.openVerification.title
proofOfPlay.whyCards.openVerification.desc
proofOfPlay.whyCards.closedDiscovery.title
proofOfPlay.whyCards.closedDiscovery.desc
proofOfPlay.whyCards.uniquePerImpression.title
proofOfPlay.whyCards.uniquePerImpression.desc