Skip to content

GPU Compute Rental

Record per-customer GPU-hours with the Balance API so the team paying the bill can check the same record the invoice was built from.

This example records GPU compute rental: per-GPU-hour usage metered by the compute provider, flushed daily as verified deltas, locked at period end, and delivered with a proof the customer's FinOps team can check independently. The mechanism is identical to SaaS metering and inference billing; only the unit changes.

Prerequisites

  • A Balance API key
  • Node.js 18+ or Python 3.8+
  • The PacSpace SDK (npm install @pacspace-io/sdk) or requests library for Python

The Workflow

  1. Flush daily GPU-hours - each 24-hour metering window becomes one verified delta per customer
  2. Break out clusters with metadata - tag deltas so both sides can trace a day's total to a cluster or reservation
  3. Lock the period - checkpoint at month-end to freeze the billing window
  4. Invoice with the proof - embed the proof root and verification link so the FinOps team can check GPU-hours without asking you for logs

Step 1: Flush Daily GPU-Hours

At the end of each metering day, aggregate a customer's GPU-hours across their clusters in your own system, then emit one delta for the window. Utilization measurement stays in your metering stack; PacSpace records what you attest and makes it checkable.

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

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

async function flushDailyGpuHours(
  customerId: string,
  usageDate: string,
  gpuHours: number,
  cluster: string,
) {
  const result = await pac.balance.emit(
    customerId,
    -gpuHours,
    `daily_usage_flush:${usageDate}`,
    {
      referenceId: `usage:${customerId}:${cluster}:${usageDate}`,
      metadata: {
        resource: 'gpu-hours',
        cluster,
      },
    },
  );

  console.log(`Flushed ${gpuHours} GPU-hours for ${customerId} (${cluster}) on ${usageDate}`);
  return result;
}

Flushing per cluster keeps reference IDs stable and idempotent per cluster-day. If you bill at the account level only, flush one delta per customer per day instead; the verification is identical either way. See Deltas & Flush Cadence.

Step 2: Mid-Period Visibility for FinOps

Reserved-capacity and on-demand GPU spend is exactly the kind of number a FinOps team wants to watch between invoices. Derive the running balance at any time; with a Shared Record link on the invoice, the customer can watch it without asking you.

typescript
const balance = await pac.balance.derive('cust_render_042', { granularity: 'day' });

console.log(`GPU-hours this period: ${Math.abs(balance.computedBalance)}`);
console.log(`Verified daily flushes: ${balance.deltasCount}`);

Step 3: Lock the Period

At month-end, checkpoint to freeze the billing window. The proof root covers every verified daily delta in the period.

typescript
const checkpoint = await pac.balance.checkpoint('cust_render_042', {
  period: '2026-06',
});

console.log(`Period locked. Proof root: ${checkpoint.proofRoot}`);

Step 4: Invoice With the Proof

Pull the receipt and put the proof on the invoice next to the line items.

typescript
async function generateGpuInvoice(customerId: string, period: string, ratePerGpuHour: number) {
  const checkpoint = await pac.balance.checkpoint(customerId, { period });
  const receipt = await pac.balance.receipt(customerId, { period });
  const gpuHours = Math.abs(receipt.finalBalance);

  return {
    invoiceId: `inv-${customerId}-${period}`,
    customerId,
    period,
    gpuHours,
    recordedDays: receipt.deltaCount,
    ratePerGpuHour,
    subtotal: gpuHours * ratePerGpuHour,
    proofRoot: receipt.proofRoot ?? checkpoint.proofRoot,
    verifyUrl: receipt.verifyUrl,
  };
}

const invoice = await generateGpuInvoice('cust_render_042', '2026-06', 2.10);

Expected Output

============================================================
  INVOICE: inv-cust_render_042-2026-06
============================================================
  Customer:           cust_render_042
  Period:             2026-06
  GPU-Hours:          11,520
  Recorded Days:      30
  Rate:               $2.10 / GPU-hour
  Subtotal:           $24,192.00
  Proof root:         0x4c81d7e2...
  Verify at:          https://customer-links.pacspace.io/c/cus_render042
============================================================

The customer's FinOps team opens the verification link, checks the recorded GPU-hours against their own scheduler's view, and uses Compare if the numbers diverge. The conversation, if one is needed, starts from a specific cluster-day rather than a disputed monthly total.

Why This Works for Compute Rental

Utilization disputes in GPU rental follow one shape: the provider's scheduler metered hours the customer's own tracking did not see, or priced idle time the customer did not expect. The meter lives inside the provider, so the customer cannot run a parallel one. Recording each cluster-day as a verified delta before the invoice means both sides point at the same record when the question comes up, and the record already existed before anyone asked.

Next Steps