Quick Start
Get up and running with Vertifile in three steps. Protect your first document in under five minutes.
1

Get Your API Key

Sign up for a Vertifile organization account and generate an API key from your dashboard settings.

2

Install the SDK

Install our official SDK for Node.js or Python, or use the REST API directly with cURL.

3

Protect a Document

Upload any file to create a tamper-proof .pvf document with embedded verification.

Install
# Node.js
npm install vertifile

# Python
pip install vertifile
Authentication
All API requests require authentication via an API key passed in the request header.

Include your API key in every request using the X-API-Key header:

Request Header
X-API-Key: your_api_key_here
Keep your API key secret. Never expose it in client-side code or public repositories. Use environment variables to store it securely.

The API base URL depends on your deployment. For the hosted service, use:

Base URL
https://api.vertifile.com
Code Examples
Full examples for creating protected documents, verifying them, and using the gateway API.

Create a Protected Document

Node.js
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

Node.js
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

Node.js
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

Python
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

Python
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

Python
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

cURL
# 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

cURL
# 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

cURL
# 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

cURL
# 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

cURL
# 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"
API Endpoints
Complete reference for all available API endpoints.
POST /api/create-pvf

Upload a file and receive a tamper-proof .pvf document. Optionally bind the document to a specific recipient email.

Parameters
file file required
The document file to protect. Sent as multipart/form-data.
recipient string optional
Email address to bind the document to a specific recipient.
Headers
X-API-Key string required
Your organization API key.
Response

Returns the .pvf HTML file as a binary download.

POST /api/verify

Verify a document's authenticity by its cryptographic hash and signature.

Body (JSON)
hash string required
The SHA-256 hash of the original document content.
signature string required
The cryptographic signature embedded in the .pvf file.
POST /api/gateway/intake

Organizations send a .pvf file for server-side verification and extraction of the original document.

Parameters
file file required
The .pvf file to verify and extract. Sent as multipart/form-data.
Headers
X-API-Key string required
Your organization API key.
POST /api/gateway/batch New

Batch verification of multiple .pvf documents in a single request.

Parameters
files file[] required
Multiple .pvf files to verify. Sent as multipart/form-data.
GET /api/org/stats

Retrieve usage statistics for your organization, including document counts and verification metrics.

GET /api/org/documents

List all documents created by your organization. Supports pagination.

Query Parameters
page integer optional
Page number (default: 1).
limit integer optional
Results per page (default: 20, max: 100).
POST /api/webhooks/register

Register a webhook URL to receive real-time notifications for verification events.

Body (JSON)
url string required
The HTTPS URL to receive webhook POST requests.
events string[] required
Event types to subscribe to: document.verified, document.failed, document.created.
secret string optional
A shared secret for signing webhook payloads (recommended).
Webhook Integration
Receive real-time notifications when documents are verified or created.

Register a Webhook

Node.js
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

Node.js (Express)
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 });
});
Webhook payloads are signed with your shared secret using HMAC-SHA256. Always verify the x-vertifile-signature header before processing events.
Available Events
EventDescription
document.createdA new .pvf document was created via the API
document.verifiedA document was successfully verified
document.failedA document verification attempt failed
Response Examples
Typical JSON responses from the API.

Verification Success

POST /api/verify — 200 OK
{
  "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

POST /api/verify — 200 OK
{
  "success": true,
  "verified": false,
  "reason": "Document hash does not match any known record"
}

Gateway Intake Response

POST /api/gateway/intake — 200 OK
{
  "success": true,
  "verified": true,
  "document": {
    "id": "doc_8f3a1b2c4d5e",
    "filename": "contract.pdf",
    "mimeType": "application/pdf",
    "size": 245780
  },
  "originalFile": "JVBERi0xLjQKMS..." // base64-encoded
}

Organization Stats

GET /api/org/stats — 200 OK
{
  "success": true,
  "stats": {
    "totalDocuments": 1284,
    "totalVerifications": 3891,
    "documentsThisMonth": 142,
    "verificationsThisMonth": 467,
    "plan": "business",
    "usage": {
      "documentsUsed": 142,
      "documentsLimit": 500
    }
  }
}

Webhook Registration

POST /api/webhooks/register — 201 Created
{
  "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

Error — 401 Unauthorized
{
  "success": false,
  "error": "Invalid or missing API key",
  "code": "UNAUTHORIZED"
}
Rate Limits
Rate limits are applied per API key to ensure fair usage for all users.
When you exceed a rate limit, the API returns a 429 Too Many Requests response with a Retry-After header indicating when you can retry.
Verifications (the /api/verify endpoint) are always free and unlimited. Only document creation counts toward your quota.

For details about plans and limits, contact us.