TrustVerify logo
DocsRegulatory evidence bundles

Regulatory evidence bundles

Generate and verify RPT-016 signed ZIP archives for regulator submission.

RPT-016 is a signed ZIP archive produced for regulatory submission. It contains an executive PDF summary, a SHA-256 manifest of every evidence file, and a HMAC-SHA-256 signature across the entire bundle.

Bundle structure

ZIP STRUCTURE
RPT-016-{checkId}.zip
├── executive-summary.pdf       # Human-readable cover report
├── manifest.sha256.json        # SHA-256 hash of every file
├── signature.hmac              # HMAC-SHA-256 over manifest
├── kyc/
│   ├── RPT-001-{checkId}.pdf
│   └── liveness-session.json
├── aml/
│   ├── RPT-003-{checkId}.pdf
│   └── sanctions-raw.json
└── audit/
    └── RPT-015-{checkId}.pdf

Generating a bundle

CURL
curl -X POST https://api.trustverify.co.uk/api/v1/reports/rpt-016 \
  -H "Authorization: Bearer tv_live_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "checkId":      "chk_01J8KX9QMN23PQRST",
    "includeTypes": ["RPT-001","RPT-003","RPT-015"],
    "regulatorRef": "FCA-2026-00142"
  }'
# Response: { "bundleId": "bnd_abc123", "status": "generating", "estimatedReadyAt": "…" }

Verifying the HMAC signature

NODE.JS
import crypto from 'crypto';
import fs      from 'fs';

const manifest  = fs.readFileSync('manifest.sha256.json');
const signature = fs.readFileSync('signature.hmac', 'utf8').trim();
const secret    = process.env.TV_WEBHOOK_SECRET!;

const expected = crypto
  .createHmac('sha256', secret)
  .update(manifest)
  .digest('hex');

const isValid = crypto.timingSafeEqual(
  Buffer.from(signature, 'hex'),
  Buffer.from(expected,  'hex'),
);

console.log(isValid ? '✓ Bundle is authentic' : '✗ Signature mismatch');

Always verify the HMAC signature before submitting a bundle to a regulator. A failed signature check means the bundle was modified after TrustVerify signed it.