Skip to content

Query — Derive a Balance

Derive a running balance from all verified deltas for a customer. Supports checkpointing for efficient pagination.

Use this endpoint to compute a customer's current balance by replaying all verified deltas. For large histories, use checkpoints to resume from a known point instead of replaying from the beginning.


Endpoint

GET https://balance-api.pacspace.io/api/v1/balance/derive/:customerId

Headers

HeaderRequiredDescription
X-Api-KeyYesYour PacSpace API key

Path Parameters

ParameterTypeRequiredDescription
customerIdstringYesUnique identifier for the customer account

Query Parameters

ParameterTypeRequiredDefaultDescription
startingBalancenumberNo0Initial balance to start the derivation from
startingCheckpointstringNoResume derivation from a previous checkpoint
startingCheckpointTypestringNoitemsRootType of checkpoint: itemsRoot or anchorId
limitnumberNo100Number of deltas per page (1–1000). Balance is always computed from all deltas.
offsetnumberNo0Number of deltas to skip for pagination.

Examples

SDK (TypeScript)

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

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

// Simple query — derive from zero
const result = await pac.balance.derive('cust_12345');
console.log(result.computedBalance);
console.log(result.deltasCount);

// With checkpoint — resume from a known point
const next = await pac.balance.derive('cust_12345', {
  startingBalance: result.computedBalance,
  startingCheckpoint: result.latestReceiptId,
});

Simple Query

Derive a balance from zero, replaying all verified deltas.

cURL

bash
curl -X GET "https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345" \
  -H "X-Api-Key: YOUR_API_KEY"

JavaScript (Node.js)

javascript
const response = await fetch(
  "https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345",
  {
    headers: {
      "X-Api-Key": "YOUR_API_KEY",
    },
  }
);

const result = await response.json();
console.log(result);

Python

python
import requests

response = requests.get(
    "https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345",
    headers={"X-Api-Key": "YOUR_API_KEY"},
)

result = response.json()
print(result)

Query with Checkpoint

Resume from a previous checkpoint to avoid replaying the entire delta history. This is useful for accounts with many transactions.

cURL

bash
curl -X GET "https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345?\
startingBalance=50000&\
startingCheckpoint=0xdef456...&\
startingCheckpointType=itemsRoot" \
  -H "X-Api-Key: YOUR_API_KEY"

JavaScript (Node.js)

javascript
const params = new URLSearchParams({
  startingBalance: "50000",
  startingCheckpoint: "0xdef456...",
  startingCheckpointType: "itemsRoot",
});

const response = await fetch(
  `https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345?${params}`,
  {
    headers: {
      "X-Api-Key": "YOUR_API_KEY",
    },
  }
);

const result = await response.json();
console.log(result);

Python

python
import requests

response = requests.get(
    "https://balance-api.pacspace.io/api/v1/balance/derive/cust_12345",
    headers={"X-Api-Key": "YOUR_API_KEY"},
    params={
        "startingBalance": 50000,
        "startingCheckpoint": "0xdef456...",
        "startingCheckpointType": "itemsRoot",
    },
)

result = response.json()
print(result)

Response

json
{
  "success": true,
  "data": {
    "customerId": "cust_12345",
    "startingBalance": 0,
    "startingCheckpoint": "genesis",
    "startingCheckpointType": "itemsRoot",
    "computedBalance": 48500,
    "deltasCount": 127,
    "latestCheckpoint": "0xabc789...",
    "latestReceiptId": "0xabc789...",
    "deltas": [
      {
        "anchorId": "a_1234567890",
        "itemHash": "0x2d4e7f1a...",
        "itemsRoot": "0x8f3a9b2c...",
        "receiptId": "0x8f3a9b2c...",
        "delta": -1000,
        "reason": "Monthly subscription charge",
        "referenceId": "inv_98765",
        "window": "2026-02",
        "declaredTimestamp": "2026-02-10T14:30:00Z",
        "blockTimestamp": "2026-02-10T14:30:12Z",
        "dataPurged": false,
        "verified": true
      }
    ],
    "windowSummaries": [
      {
        "window": "2026-01",
        "deltasCount": 42,
        "netDelta": 1500,
        "firstBlockTimestamp": "2026-01-03T10:15:00Z",
        "lastBlockTimestamp": "2026-01-31T22:45:00Z"
      }
    ],
    "verificationProof": {
      "itemsRoot": "0xabc789...",
      "message": "Proof root covers all deltas in this derivation."
    }
  }
}

Response Fields

FieldTypeDescription
customerIdstringThe customer account the balance was derived for
startingBalancenumberThe initial balance used for derivation
startingCheckpointstringCheckpoint the derivation started from ("genesis" if from beginning)
startingCheckpointTypestringType of checkpoint used: itemsRoot or anchorId
computedBalancenumberThe derived running balance after replaying all deltas
deltasCountnumberTotal number of verified deltas included in the derivation
latestCheckpointstring | nullCheckpoint value you can use in subsequent queries to resume here
latestReceiptIdstring | nullReceipt ID of the most recent delta (same as latestCheckpoint)
deltasarrayList of individual delta records included in the derivation
windowSummariesarrayAggregated summaries grouped by time window
verificationProofobjectCryptographic proof that the derivation is correct and untampered

Delta Object

FieldTypeDescription
anchorIdstringUnique identifier for this delta
itemHashstringContent hash of this individual delta
itemsRootstringProof root covering this delta
receiptIdstringReceipt identifier (same as itemsRoot)
deltanumberThe adjustment amount
reasonstringHuman-readable reason for the adjustment
referenceIdstringYour external reference ID, or null if not provided
windowstringTime window label (e.g., 2026-02)
declaredTimestampstringISO 8601 timestamp you declared when submitting
blockTimestampstringISO 8601 timestamp of when verification completed
dataPurgedbooleanWhether the raw business data has been purged per retention policy
verifiedbooleanWhether the delta has been verified

Window Summary Object

FieldTypeDescription
windowstringTime window label (e.g., 2026-01)
deltasCountnumberNumber of deltas in the window
netDeltanumberNet balance change for the window
firstBlockTimestampstringISO 8601 timestamp of the first delta in the window
lastBlockTimestampstringISO 8601 timestamp of the last delta in the window

Verification Proof Object

FieldTypeDescription
itemsRootstringProof root hash covering all deltas in the derivation
messagestringHuman-readable description of the proof

Pagination

The deltas array in the response is paginated. The pagination object shows the total count and current page:

json
{
  "pagination": {
    "total": 5420,
    "limit": 100,
    "offset": 0
  }
}

The computedBalance is always derived from all verified deltas, regardless of pagination. Only the deltas array in the response is paginated — the balance calculation considers every delta.


Scaling with Checkpoints

For customers with large delta counts (1,000+), the response includes a _hint suggesting checkpoint-based derivation. At 50,000+ deltas, a startingCheckpoint is required.

Use latestCheckpoint from a previous derive response as startingCheckpoint for incremental derivation:

bash
# First derivation
GET /api/v1/balance/derive/cust_123

# Subsequent derivation (incremental)
GET /api/v1/balance/derive/cust_123?startingBalance=95000&startingCheckpoint=0xabc...

This keeps response times fast and avoids replaying tens of thousands of deltas on every query. When the _hint is present, it includes the recommended startingCheckpoint value to use.


Using Checkpoints

Checkpoints let you avoid replaying the entire delta history on every query. Here's the recommended workflow:

  1. First query — Call without checkpoint parameters. The response includes a latestCheckpoint and the computedBalance.

  2. Store the checkpoint — Save the latestCheckpoint value and computedBalance on your side.

  3. Subsequent queries — Pass startingBalance (the previously computed balance) and startingCheckpoint (the stored checkpoint). PacSpace only replays deltas recorded after that checkpoint.

Tip: Combine checkpoints with the Checkpoint endpoint to lock period-end snapshots for billing reconciliation.