Skip to content

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


Full Example

javascript
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

  1. 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.

  2. Derive the balance - The derive call reads verified deltas for the default scope (current UTC month) and returns computedBalance plus the latest checkpoint you can resume from.

  3. 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 returns matchesYours, matchesTheirs, a discrepancyReport pointing 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