Skip to content

Vendor Cost Tracking

Use the Balance API to build a verifiable, tamper-evident record of your infrastructure costs. Automate vendor bill ingestion, compare against internal metrics, and generate verifiable proofs of every dollar spent.

Vendor Cost Tracking with PacSpace

Turn your infrastructure spend into a verifiable audit trail. Every cost event becomes a permanently recorded delta — tamper-evident, independently verifiable, and immutable.


Why Track Vendor Costs with PacSpace?

Traditional cost tracking stores numbers in spreadsheets or dashboards that can be silently modified. The Balance API gives you something different:

  • Tamper-evident records — every cost delta is permanently recorded on the verification layer. No one can quietly edit a historical cost entry.
  • Vendor bill verification — compare what your vendors charge against what your systems actually consumed. Discrepancies are permanently recorded.
  • Audit-ready proofs — generate verifiable receipts per vendor per period. Board-ready, auditor-ready, regulator-ready.
  • Real-time visibility — customer ledgers give you a live view of cumulative spend per vendor, updated as deltas verify.

Use cases:

  • Startups reporting COGS to investors
  • Enterprises auditing cloud spend across teams
  • Regulated industries requiring verifiable cost records
  • Any company that wants to prove their infrastructure costs are accurate

Step 1: Design Your Customer ID Schema

Each vendor or service gets a unique customerId. This creates an isolated ledger per cost center.

Naming Convention

Use {vendor}-{service} format, lowercase and hyphen-separated:

gcp-cloudrun-api        # GCP Cloud Run — API service
gcp-cloudsql            # GCP Cloud SQL database
stripe                  # Stripe processing fees
sendgrid                # SendGrid email delivery
aws-s3                  # AWS S3 storage
datadog                 # Datadog monitoring

Granularity Decision

Choose the right level of detail for your needs:

ApproachExampleBest For
Per servicegcp-cloudrun-api, gcp-cloudrun-workerDetailed cost attribution
Per vendorgcp, stripe, sendgridSimple cost tracking
Per categorycompute, data, commsHigh-level COGS reporting

You can always start coarse and add granularity later — each new customerId automatically creates a new ledger.


Step 2: Set Up Automated Ingestion

Build a script or service that pulls billing data from each vendor and emits deltas via the SDK.

Install the SDK

bash
npm install @pacspace/sdk

Initialize the Client

typescript
import { PacSpace } from '@pacspace/sdk';

const pac = new PacSpace({
  apiKey: process.env.PACSPACE_API_KEY,
});

Step 3: Emit Deltas for Each Cost Event

Cloud Provider Billing (GCP BigQuery Export)

typescript
import { BigQuery } from '@google-cloud/bigquery';

const bigquery = new BigQuery();

async function ingestGcpCosts(date: string) {
  const [rows] = await bigquery.query({
    query: `
      SELECT service.description, SUM(cost) AS cost
      FROM \`my-project.billing_export.gcp_billing\`
      WHERE DATE(usage_start_time) = '${date}'
      GROUP BY service.description
    `,
  });

  for (const row of rows) {
    const customerId = mapServiceToCustomerId(row.description);

    await pac.balance.emit(customerId, -row.cost, 'gcp_daily_cost', {
      referenceId: `gcp:${customerId}:${date}`,
      metadata: {
        date,
        vendorReported: {
          cost: row.cost,
          source: 'gcp_billing_export',
          service: row.description,
        },
      },
    });
  }
}

Payment Processor (Stripe)

typescript
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY);

async function ingestStripeFees(date: string) {
  const dayStart = Math.floor(new Date(`${date}T00:00:00Z`).getTime() / 1000);
  const dayEnd = dayStart + 86400;

  let totalFees = 0;

  for await (const txn of stripe.balanceTransactions.list({
    created: { gte: dayStart, lt: dayEnd },
  })) {
    totalFees += txn.fee / 100; // cents → dollars
  }

  if (totalFees > 0) {
    await pac.balance.emit('stripe', -totalFees, 'stripe_processing_fee', {
      referenceId: `stripe:daily:${date}`,
      metadata: {
        date,
        vendorReported: { cost: totalFees, source: 'stripe_balance_transactions' },
      },
    });
  }
}

SaaS Subscriptions (Fixed Monthly Cost)

typescript
// For vendors with fixed monthly pricing (SendGrid, Datadog, etc.)
async function emitMonthlyCost(
  customerId: string,
  monthlyCost: number,
  period: string, // '2026-02'
  vendorName: string,
) {
  await pac.balance.emit(customerId, -monthlyCost, `${vendorName}_monthly`, {
    referenceId: `${customerId}:${period}`,
    metadata: {
      period,
      vendorReported: {
        cost: monthlyCost,
        source: 'manual_plan_cost',
        currency: 'USD',
      },
    },
  });
}

// Examples
await emitMonthlyCost('sendgrid', 19.95, '2026-02', 'sendgrid');
await emitMonthlyCost('datadog', 249.00, '2026-02', 'datadog');

Batch Emit for Multiple Services

When you have many cost lines (e.g., 13 GCP services), use batch emit:

typescript
const deltas = gcpServices.map(svc => ({
  customerId: svc.customerId,
  delta: -svc.cost,
  reason: 'gcp_daily_cost',
  referenceId: `gcp:${svc.customerId}:${date}`,
  metadata: { date, vendorReported: { cost: svc.cost } },
}));

const result = await pac.balance.emitBatch(deltas);
console.log(`Queued: ${result.totalQueued}, Failed: ${result.totalFailed}`);

Step 4: Enrich with Internal Metrics (Trust but Verify)

For maximum value, include your own usage measurements alongside vendor-reported costs:

typescript
await pac.balance.emit('gcp-cloudrun-api', -4.23, 'gcp_daily_cost', {
  metadata: {
    vendorReported: {
      cost: 4.23,
      source: 'gcp_billing_export',
      usage_amount: 1440,
      usage_unit: 'vCPU-minutes',
    },
    internalMeasured: {
      requestCount: 12847,
      cpuMinutes: 1440,
      source: 'cloud_monitoring_api',
    },
    aligned: true,
    discrepancyNote: null,
  },
});

When vendor and internal measurements diverge:

typescript
{
  aligned: false,
  discrepancyNote: 'Vendor reported 1500 vCPU-minutes but Cloud Monitoring recorded 1440 (4% diff)',
}

These discrepancies are permanently anchored — creating an immutable audit trail for vendor disputes.


Step 5: Monthly Reconciliation

At month-end, run the full reconciliation cycle:

typescript
const vendors = ['gcp-cloudrun-api', 'gcp-cloudsql', 'stripe', 'sendgrid', ...];

for (const vendorId of vendors) {
  // 1. Checkpoint — lock the period summary
  const checkpoint = await pac.balance.checkpoint(vendorId, { period: '2026-02' });
  console.log(`${vendorId}: proof root ${checkpoint.merkleRoot}`);

  // 2. Derive — compute the total balance
  const derived = await pac.balance.derive(vendorId);
  console.log(`${vendorId}: balance $${derived.computedBalance}`);

  // 3. Receipt — generate audit-ready proof
  const proof = await pac.balance.receipt(vendorId, { period: '2026-02' });
  console.log(`${vendorId}: proof root ${proof.proofRoot}`);

  // 4. Compare — verify against actual invoice
  const report = await pac.balance.compare(vendorId, {
    yours: derived.computedBalance,
    theirs: actualInvoiceAmount,
  });

  if (!report.matchesTheirs) {
    console.warn(`DISCREPANCY: ${vendorId} — our records show $${derived.computedBalance} but invoice says $${actualInvoiceAmount}`);
  }
}

Step 6: Build a COGS Dashboard

Use the Customer Ledgers list endpoint to build a real-time cost dashboard:

typescript
// Get all vendor ledgers
const ledgers = await pac.balance.customers();

// Get aggregate summary
const summary = await pac.balance.customersSummary();
console.log(`Total COGS: $${Math.abs(summary.totalBalance)}`);
console.log(`Vendors tracked: ${summary.ledgerCount}`);
console.log(`Total cost events: ${summary.totalDeltas}`);

Or use the built-in Customer Ledgers page in the PacSpace dashboard for an instant visual overview.


Automation Schedule

CadenceSourcesWhat Runs
DailyCloud provider billing, Stripe feesPull yesterday's costs, emit deltas
MonthlySaaS subscriptions, GitHub, SendGridEmit fixed costs, run reconciliation

Deploy with Cloud Scheduler, AWS EventBridge, or any cron-like service:

bash
# Daily at 6 AM
0 6 * * * node dogfood/index.ts --mode=daily

# Monthly on the 1st at 8 AM
0 8 1 * * node dogfood/index.ts --mode=monthly

What You Get

After setup, you have:

  1. Per-vendor ledgers — isolated cost history for every service you pay for
  2. Verifiable proofs — proof roots permanently recorded for each period
  3. Discrepancy detection — automatic flagging when vendor bills don't match your measurements
  4. Audit trail — every cost event is immutable and independently verifiable
  5. Real-time dashboard — live COGS visibility via Customer Ledgers

This is the same system PacSpace uses internally to track its own infrastructure costs — battle-tested on real production data.