Get Your API Key
Sign up for a Vertifile organization account and generate an API key from your dashboard settings.
Install the SDK
Install our official SDK for Node.js or Python, or use the REST API directly with cURL.
Protect a Document
Upload any file to create a tamper-proof .pvf document with embedded verification.
# Node.js
npm install vertifile
# Python
pip install vertifile
Include your API key in every request using the X-API-Key header:
X-API-Key: your_api_key_here
The API base URL depends on your deployment. For the hosted service, use:
https://api.vertifile.com
Create a Protected Document
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');
const API_KEY = 'your_api_key_here';
const BASE_URL = 'https://api.vertifile.com';
async function createPvf(filePath, recipientEmail) {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
// Optional: bind document to a specific recipient
if (recipientEmail) {
form.append('recipient', recipientEmail);
}
const response = await axios.post(
`${BASE_URL}/api/create-pvf`,
form,
{
headers: {
'X-API-Key': API_KEY,
...form.getHeaders()
},
responseType: 'arraybuffer'
}
);
// Save the .pvf file
fs.writeFileSync('protected.pvf.html', response.data);
console.log('Document protected successfully.');
}
createPvf('./contract.pdf', 'recipient@example.com');
Verify a Document
async function verifyDocument(hash, signature) {
const response = await axios.post(
`${BASE_URL}/api/verify`,
{ hash, signature },
{
headers: { 'Content-Type': 'application/json' }
}
);
if (response.data.verified) {
console.log('Document is authentic.');
console.log('Details:', response.data.document);
} else {
console.log('Verification failed.');
}
}
Gateway: Intake & Extract
async function gatewayIntake(pvfFilePath) {
const form = new FormData();
form.append('file', fs.createReadStream(pvfFilePath));
const response = await axios.post(
`${BASE_URL}/api/gateway/intake`,
form,
{
headers: {
'X-API-Key': API_KEY,
...form.getHeaders()
}
}
);
const { verified, originalFile } = response.data;
if (verified) {
// Decode and save the extracted original file
const buffer = Buffer.from(originalFile, 'base64');
fs.writeFileSync('extracted-original.pdf', buffer);
console.log('Verified & extracted successfully.');
}
}
Create a Protected Document
import requests
API_KEY = 'your_api_key_here'
BASE_URL = 'https://api.vertifile.com'
def create_pvf(file_path, recipient=None):
"""Upload a file and receive a protected .pvf document."""
with open(file_path, 'rb') as f:
files = {'file': f}
data = {}
if recipient:
data['recipient'] = recipient
response = requests.post(
f'{BASE_URL}/api/create-pvf',
files=files,
data=data,
headers={'X-API-Key': API_KEY}
)
# Save the .pvf file
with open('protected.pvf.html', 'wb') as out:
out.write(response.content)
print('Document protected successfully.')
create_pvf('./contract.pdf', 'recipient@example.com')
Verify a Document
def verify_document(doc_hash, signature):
"""Verify a document's authenticity."""
response = requests.post(
f'{BASE_URL}/api/verify',
json={
'hash': doc_hash,
'signature': signature
}
)
result = response.json()
if result['verified']:
print('Document is authentic.')
print('Details:', result['document'])
else:
print('Verification failed.')
Gateway: Intake & Extract
import base64
def gateway_intake(pvf_path):
"""Send a .pvf file for verification and extract the original."""
with open(pvf_path, 'rb') as f:
response = requests.post(
f'{BASE_URL}/api/gateway/intake',
files={'file': f},
headers={'X-API-Key': API_KEY}
)
result = response.json()
if result['verified']:
# Decode and save the original file
original = base64.b64decode(result['originalFile'])
with open('extracted-original.pdf', 'wb') as out:
out.write(original)
print('Verified & extracted successfully.')
Create a Protected Document
# Create a .pvf from a local file
curl -X POST https://api.vertifile.com/api/create-pvf \
-H "X-API-Key: your_api_key_here" \
-F "file=@contract.pdf" \
-F "recipient=recipient@example.com" \
-o protected.pvf.html
Verify a Document
# Verify using hash and signature
curl -X POST https://api.vertifile.com/api/verify \
-H "Content-Type: application/json" \
-d '{
"hash": "a1b2c3d4e5f6...",
"signature": "3045022100..."
}'
Gateway: Intake & Extract
# Send a .pvf for verification + extraction
curl -X POST https://api.vertifile.com/api/gateway/intake \
-H "X-API-Key: your_api_key_here" \
-F "file=@document.pvf.html"
Batch Verification
# Batch verify multiple documents
curl -X POST https://api.vertifile.com/api/gateway/batch \
-H "X-API-Key: your_api_key_here" \
-F "files=@doc1.pvf.html" \
-F "files=@doc2.pvf.html" \
-F "files=@doc3.pvf.html"
Organization Stats
# Get organization statistics
curl https://api.vertifile.com/api/org/stats \
-H "X-API-Key: your_api_key_here"
# List documents (paginated)
curl "https://api.vertifile.com/api/org/documents?page=1&limit=20" \
-H "X-API-Key: your_api_key_here"
Upload a file and receive a tamper-proof .pvf document. Optionally bind the document to a specific recipient email.
Returns the .pvf HTML file as a binary download.
Verify a document's authenticity by its cryptographic hash and signature.
Organizations send a .pvf file for server-side verification and extraction of the original document.
Batch verification of multiple .pvf documents in a single request.
Retrieve usage statistics for your organization, including document counts and verification metrics.
List all documents created by your organization. Supports pagination.
Register a webhook URL to receive real-time notifications for verification events.
document.verified, document.failed, document.created.Register a Webhook
async function registerWebhook() {
const response = await axios.post(
`${BASE_URL}/api/webhooks/register`,
{
url: 'https://yourapp.com/webhooks/vertifile',
events: ['document.verified', 'document.failed'],
secret: 'whsec_your_secret_here'
},
{
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
}
}
);
console.log('Webhook registered:', response.data);
}
Handle Incoming Webhooks
const crypto = require('crypto');
const express = require('express');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = 'whsec_your_secret_here';
function verifySignature(payload, receivedSig) {
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(receivedSig)
);
}
app.post('/webhooks/vertifile', (req, res) => {
const signature = req.headers['x-vertifile-signature'];
// Verify the webhook signature
if (!verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const { event, data } = req.body;
switch (event) {
case 'document.verified':
console.log('Document verified:', data.documentId);
// Handle successful verification
break;
case 'document.failed':
console.log('Verification failed:', data.reason);
// Handle failed verification
break;
}
res.status(200).json({ received: true });
});
x-vertifile-signature header before processing events.| Event | Description |
|---|---|
document.created | A new .pvf document was created via the API |
document.verified | A document was successfully verified |
document.failed | A document verification attempt failed |
Verification Success
{
"success": true,
"verified": true,
"document": {
"id": "doc_8f3a1b2c4d5e",
"filename": "contract.pdf",
"createdAt": "2025-01-15T10:30:00Z",
"hash": "a1b2c3d4e5f6...",
"recipient": "john@example.com",
"organization": "Acme Corp"
}
}
Verification Failure
{
"success": true,
"verified": false,
"reason": "Document hash does not match any known record"
}
Gateway Intake Response
{
"success": true,
"verified": true,
"document": {
"id": "doc_8f3a1b2c4d5e",
"filename": "contract.pdf",
"mimeType": "application/pdf",
"size": 245780
},
"originalFile": "JVBERi0xLjQKMS..." // base64-encoded
}
Organization Stats
{
"success": true,
"stats": {
"totalDocuments": 1284,
"totalVerifications": 3891,
"documentsThisMonth": 142,
"verificationsThisMonth": 467,
"plan": "business",
"usage": {
"documentsUsed": 142,
"documentsLimit": 500
}
}
}
Webhook Registration
{
"success": true,
"webhook": {
"id": "wh_9a8b7c6d5e4f",
"url": "https://yourapp.com/webhooks/vertifile",
"events": ["document.verified", "document.failed"],
"createdAt": "2025-01-15T10:30:00Z",
"active": true
}
}
Error Response
{
"success": false,
"error": "Invalid or missing API key",
"code": "UNAUTHORIZED"
}
429 Too Many Requests response with a Retry-After header indicating when you can retry./api/verify endpoint) are always free and unlimited. Only document creation counts toward your quota.For details about plans and limits, contact us.