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) orrequestslibrary for Python
The Workflow
- Flush daily GPU-hours - each 24-hour metering window becomes one verified delta per customer
- Break out clusters with metadata - tag deltas so both sides can trace a day's total to a cluster or reservation
- Lock the period - checkpoint at month-end to freeze the billing window
- 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.
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.
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.
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.
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
- Receipts & Verification guide - verification tiers and dispute handling
- Shared Record - the persistent per-customer link for live records
- SaaS Usage Metering - the same workflow with API-call units
- Autonomous Agent Pattern - let an agent watch the record for you