USB HSM Vault API

Issue and claim physical bearer assets (USB Keys) for secure, offline, inter-bank settlements.

Introduction

The USB Vault API allows partner banks and financial institutions to issue and accept physical bearer assets (H-Keys) interoperably. This service operates on a dedicated endpoint and is designed for server-to-server communication.

Workflows: Inter-Bank Settlement

1. Issuance Workflow (Bank A)

When a partner bank (Bank A) wishes to create a USB key for its client, it calls the /issue endpoint. CashPay **immediately debits Bank A's fleet account** for the key's value plus any issuance fees. The funds are then "vaulted" in an isolated record within the central hardware_keys ledger. CashPay returns a signature and a ready-to-use file content. It is Bank A's responsibility to save this content as a .cpk file to deliver to its client.

2. Claim Workflow (Bank B)

When a bearer presents a USB key to another institution (Bank B), Bank B's system scans the .cpk file and calls the /claim endpoint with the extracted H-Key. CashPay verifies the key's signature, confirms it is active, and **instantly credits Bank B's fleet account** by releasing the vaulted funds. Bank B can then safely credit its customer's account.

Issue HSM Key

POST/api/v1/b2b/hsm/issue

Issues a new hardware key signature and vaults the corresponding funds, debiting the partner's fleet account.

cURL
curl -X POST 'https://api.cashpay-all.com/api/v1/b2b/hsm/issue' \
-H 'Authorization: Bearer <YOUR_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
  "amount": 1000.00,
  "currency": "USD",
  "keyPin": "1234"
}'

Success Response

JSON
{
  "success": true,
  "hsm_signature": "a1b2c3d4e5f6...",
  "key_reference": "HSM-ISSU-ABCD",
  "fileContent": "-----BEGIN CASH PAY KEY-----\nVERSION: 2.1\n..."
}

Using the API Response to Generate the .cpk File

After a successful call to the /issue endpoint, you receive the full content of the .cpk file in the `fileContent` field. Your application is responsible for saving this content into a file and delivering it to the end user. This process can be done on your server or directly on the client-side.

Example Implementation

This example shows how to call the API and then use the response to generate a .zip archive containing the .cpk file.

JavaScript
import fs from 'fs';
import fetch from 'node-fetch';
import JSZip from 'jszip';

// Assume this is loaded from environment variables
const CASHPAY_API_KEY = 'YOUR_API_KEY';

async function generateHsmKey(amount, currency, pin) {
    // 1. Call the CashPay API to get the signature and file content
    const apiResponse = await fetch('https://api.cashpay-all.com/api/v1/b2b/hsm/issue', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${CASHPAY_API_KEY}`,
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({ amount, currency, keyPin: pin })
    });
    const result = await apiResponse.json();

    if (!result.success) {
        throw new Error(`API Error: ${result.error}`);
    }

    const { hsm_signature, fileContent } = result;

    // 2. You now have the full file content. Create a ZIP archive.
    const zip = new JSZip();
    zip.file(`${hsm_signature}.cpk`, fileContent);
    const zipBuffer = await zip.generateAsync({ type: 'nodebuffer' });
    
    const zipFileName = `CashPay-Key-${hsm_signature.substring(0,8)}.zip`;
    fs.writeFileSync(zipFileName, zipBuffer);
    
    console.log(`File ${zipFileName} created successfully.`);
    return { zipFileName };
}

// Example usage:
// generateHsmKey(1000, 'USD', '1234');

Claim HSM Key

To claim a key, your application must first read the .cpk file (either directly or from within a .zip archive) to extract the unique signature. This signature is then sent to our API along with the user's PIN to validate and process the claim.

POST/api/v1/b2b/hsm/claim

Claims the value of an active hardware key using its signature, crediting the claiming partner's fleet account.

How to Implement the Claim Process

The process involves two main steps: reading the file on your server, and then calling our API. Your frontend should provide a file upload interface for your user to select their .cpk or .zip file.

Example: Handling File Upload in Node.js (with Express & JSZip)

JavaScript
import express from 'express';
import multer from 'multer';
import JSZip from 'jszip';
import fetch from 'node-fetch';

const app = express();
const upload = multer({ storage: multer.memoryStorage() });

// Function to parse the secure block and get the signature
function getSignatureFromCpk(fileContent) {
    const secureMatch = fileContent.match(/\[SECURE-DATA-BLOCK\]\n([\s\S]*?)\n\[\/SECURE-DATA-BLOCK\]/);
    if (!secureMatch || !secureMatch[1]) {
        throw new Error("Invalid .cpk file format.");
    }
    const decoded = Buffer.from(secureMatch[1].trim(), 'base64').toString('utf-8');
    const data = JSON.parse(decoded);
    if (!data.h) {
        throw new Error("Signature not found in .cpk payload.");
    }
    return data.h;
}

// The API route on your server to handle the claim
app.post('/claim-hsm-key', upload.single('hsmFile'), async (req, res) => {
    if (!req.file) {
        return res.status(400).json({ error: 'No file uploaded.' });
    }
    
    const { pin } = req.body;
    if (!pin) {
        return res.status(400).json({ error: 'PIN is required.' });
    }

    try {
        let cpkContent;
        if (req.file.originalname.endsWith('.zip')) {
            const zip = await JSZip.loadAsync(req.file.buffer);
            const cpkFile = Object.values(zip.files).find(f => f.name.endsWith('.cpk'));
            if (!cpkFile) throw new Error("No .cpk file found in ZIP archive.");
            cpkContent = await cpkFile.async('string');
        } else {
            cpkContent = req.file.buffer.toString('utf-8');
        }

        const signature = getSignatureFromCpk(cpkContent);

        // Now, call the CashPay API
        const cashPayResponse = await fetch('https://api.cashpay-all.com/api/v1/b2b/hsm/claim', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${process.env.CASHPAY_API_KEY}`,
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({ signature: signature, keyPin: pin })
        });
        
        const cashPayResult = await cashPayResponse.json();

        if (!cashPayResponse.ok) {
            throw new Error(cashPayResult.error || 'Failed to claim key.');
        }

        res.json(cashPayResult);

    } catch (error) {
        res.status(500).json({ error: error.message });
    }
});

// Example frontend call to this route would be a multipart/form-data request

Check Key Status

GET/api/v1/b2b/hsm/status/:signature

Checks the current status of a hardware key (active, claimed, or cancelled).

Example Response

JSON
{
  "success": true,
  "status": "active" 
}

Cancel HSM Key

POST/api/v1/b2b/hsm/:signature/cancel

Cancels an 'active' key that you have issued. The vaulted funds are returned to your fleet account.

Success Response

JSON
{
  "success": true,
  "message": "Clé HSM annulée et fonds remboursés."
}