Get Your API Key
Sign up for a Vertifile organization account and generate an API key from your dashboard settings.
Call the REST API
Use the REST API directly from any language — copy-paste examples for cURL, Node.js, and Python are below.
Protect a Document
Upload any file to create a tamper-evident .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-evident .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.