Basic Recordation
A minimal usage-based billing flow: flush daily usage, derive the balance, compare with the customer.
This example flushes metered usage once every 24 hours, derives the running balance at period end, and compares your view against the customer's before an invoice goes out.
Prerequisites
- A PacSpace account with a provisioned environment
- An API key (see API Key Management)
Full Example
const API_BASE = 'https://app.pacspace.io';
const API_KEY = process.env.PACSPACE_API_KEY; // pk_live_PUBLIC.SECRET
async function pacspace(method, path, body = null) {
const options = {
method,
headers: {
'X-Api-Key': API_KEY,
'Content-Type': 'application/json'
}
};
if (body) options.body = JSON.stringify(body);
const response = await fetch(`${API_BASE}${path}`, options);
if (!response.ok) {
const error = await response.json();
throw new Error(`PacSpace error ${response.status}: ${error.message}`);
}
return response.json();
}
async function flushDailyUsage(customerId, usageDate, totalUnits) {
const { data } = await pacspace('POST', '/api/v1/balance/delta', {
customerId,
delta: -totalUnits,
reason: `daily_usage_flush:${usageDate}`,
referenceId: `usage:${customerId}:${usageDate}`,
});
console.log(`Flushed ${totalUnits} units for ${customerId} on ${usageDate} -> ${data.recordId}`);
return data;
}
async function deriveBalance(customerId) {
const { data } = await pacspace('GET', `/api/v1/balance/derive/${customerId}`);
console.log(
`Balance for ${customerId}: ${data.computedBalance} across ${data.deltasCount} verified deltas`
);
return data;
}
async function compareWithCustomer(customerId, yourBalance, customerBalance, startingBalance) {
const { data } = await pacspace('POST', '/api/v1/balance/compare', {
customerId,
yourBalance,
theirBalance: customerBalance,
startingBalance,
});
if (data.matchesYours && data.matchesTheirs) {
console.log(`Agreement confirmed: both sides agree on ${data.neutralBalance}`);
return { agreed: true, balance: data.neutralBalance };
}
console.log(
`Discrepancy of ${data.discrepancyReport?.amount} (${data.discrepancyReport?.divergentParty})`
);
console.log(data.discrepancyReport?.recommendation);
return { agreed: false, report: data.discrepancyReport };
}
async function main() {
const CUSTOMER_ID = 'customer_acme';
await flushDailyUsage(CUSTOMER_ID, '2026-02-01', 100);
await flushDailyUsage(CUSTOMER_ID, '2026-02-02', 250);
await flushDailyUsage(CUSTOMER_ID, '2026-02-03', 150);
const yours = await deriveBalance(CUSTOMER_ID);
const customerClaimedBalance = yours.computedBalance;
const result = await compareWithCustomer(
CUSTOMER_ID,
yours.computedBalance,
customerClaimedBalance,
yours.startingBalance
);
if (result.agreed) {
console.log('Period closes on the verified record.');
} else {
console.log('Investigate the discrepancy before invoicing:', result.report);
}
}
main().catch(console.error);
What's Happening
-
Flush daily usage - The vendor or middleware company aggregates usage for the customer over a 24-hour metering window, then emits one delta for that day. PacSpace records the delta and returns proof fields.
-
Derive the balance - The
derivecall reads verified deltas for the default scope (current UTC month) and returnscomputedBalanceplus the latest checkpoint you can resume from. -
Compare with the customer - Submit your balance and the customer's claimed balance to
compare. PacSpace independently derives the neutral balance from verified deltas and returnsmatchesYours,matchesTheirs, adiscrepancyReportpointing at the windows where the numbers diverge, and a recommendation for resolving it.
When both sides agree with the verified record, the billing period closes with a shared source of truth.
Expected Output
Flushed 100 units for customer_acme on 2026-02-01 -> r_1234567890
Flushed 250 units for customer_acme on 2026-02-02 -> r_1234567891
Flushed 150 units for customer_acme on 2026-02-03 -> r_1234567892
Balance for customer_acme: -500 across 3 verified deltas
Agreement confirmed: both sides agree on -500
Period closes on the verified record.
Next Steps
- Lock the billing window with a proof root using Checkpoint, then share the proof with the customer so they can check the period.
- Add webhook listeners so
delta.verifiedandcheckpoint.verifiedevents can update your billing workflow. - See Autonomous Recordation Agent for a flow where the customer side reacts to mismatches.
- Review Error Handling for retry and idempotency strategies.
- Learn how to adjust recording frequency in Deltas & Flush Cadence.