Skip to content

Verify — Public Verification & Compare

Publicly verify a proof root with no authentication, or compare your balance against a counterparty's.

This page documents two verification operations: public verification (anyone with a proof root can verify) and compare (resolving balance disputes between parties).


Public Verification — Verify a Proof Root

Use this endpoint to verify a proof root. No authentication required — the proof root itself is the access key. Share it with counterparties, auditors, or autonomous systems so they can independently confirm a receipt or checkpoint.

GET https://balance-api.pacspace.io/api/v1/verify/:proofRoot

Authentication

None. This is a public endpoint. The proof root is a 256-bit content fingerprint — it cannot be guessed or enumerated. Possession of the proof root grants read-only access to that specific verification result.

Three Trust Levels

  1. Human-readable summary — The response includes verified, summary (record count, net change), and records for spot-checking.
  2. Math verification — Recompute the proof root from the records using the proof specification and confirm it matches.
  3. Public ledger — The verification.publicLedgerUrl links to the permanent record on the verification layer. Anyone can confirm the proof exists independently of PacSpace.

Example Request

bash
curl https://balance-api.pacspace.io/api/v1/verify/0x7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f

Example Response

json
{
  "success": true,
  "data": {
    "verified": true,
    "proofRoot": "0x7f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f",
    "recordedAt": "2026-02-18T14:32:00.000Z",
    "summary": {
      "recordCount": 42,
      "netChange": -6300,
      "startingBalance": 0,
      "endingBalance": -6300,
      "firstRecordAt": "2026-02-01T10:00:00.000Z",
      "lastRecordAt": "2026-02-18T14:30:00.000Z"
    },
    "records": [
      {
        "amount": -150,
        "reason": "api_call",
        "referenceId": "inv_2026_02_item_001",
        "status": "verified",
        "time": "2026-02-01T10:00:00.000Z"
      }
    ],
    "verification": {
      "reference": "0xabc123...",
      "publicLedgerUrl": "https://hashscan.io/mainnet/transaction/0xabc123...",
      "note": "This proof exists on a public verification layer that neither party controls."
    },
    "message": "This proof was permanently recorded and is independently verifiable."
  }
}

Response Fields

FieldTypeDescription
verifiedbooleanWhether the proof was found and permanently recorded
proofRootstringThe proof root that was verified
recordedAtstringWhen the proof was permanently recorded
summaryobjectAggregate: recordCount, netChange, startingBalance, endingBalance, firstRecordAt, lastRecordAt
recordsarrayIndividual records: amount, reason, status, time (and optionally referenceId, itemFingerprint)
verificationobjectreference (ledger transaction ID), publicLedgerUrl, note

Privacy

No party-identifying data is returned. Tenant ID, customer ID, and other business identifiers stay private. The response contains only the proof root, timestamps, amounts, reasons, and verification metadata — enough to confirm the math without exposing who the parties are.

Agent-Ready

This endpoint is designed for machine-speed verification by autonomous systems. Poll it to confirm a proof root exists, parse the records array for reconciliation, or follow publicLedgerUrl for full independent verification. No API keys, no sessions, no rate limits beyond standard HTTP.


Compare — Resolve Balance Disputes

Use this endpoint when two parties disagree on a balance. PacSpace independently derives the correct balance from verified deltas and reports which side (if either) has a discrepancy.

POST https://balance-api.pacspace.io/api/v1/balance/compare

Headers

HeaderRequiredDescription
X-Api-KeyYesYour PacSpace API key
Content-TypeYesMust be application/json

Request Body

ParameterTypeRequiredDescription
customerIdstringYesUnique identifier for the customer account
yourBalancenumberYesThe balance your system currently shows. Must be a finite number between -1,000,000,000 and 1,000,000,000.
theirBalancenumberYesThe balance the counterparty claims. Must be a finite number between -1,000,000,000 and 1,000,000,000.
startingBalancenumberYesAgreed-upon starting balance for the comparison window
startingCheckpointstringNoCheckpoint to begin the comparison from
startingCheckpointTypestringNoType of checkpoint: itemsRoot or anchorId

Examples

SDK (TypeScript)

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

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

const report = await pac.balance.compare('cust_12345', {
  yours: 48500,
  theirs: 49000,
}, {
  startingBalance: 50000,
  startingCheckpoint: '0xdef456...',
  startingCheckpointType: 'itemsRoot',
});

if (report.matchesYours) {
  console.log('Your balance is correct');
} else if (report.discrepancyReport) {
  console.log(`Discrepancy: ${report.discrepancyReport.amount}`);
  console.log(report.discrepancyReport.resolution);
}

cURL

bash
curl -X POST https://balance-api.pacspace.io/api/v1/balance/compare \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "cust_12345",
    "yourBalance": 48500,
    "theirBalance": 49000,
    "startingBalance": 50000,
    "startingCheckpoint": "0xdef456...",
    "startingCheckpointType": "itemsRoot"
  }'

JavaScript (Node.js)

javascript
const response = await fetch(
  "https://balance-api.pacspace.io/api/v1/balance/compare",
  {
    method: "POST",
    headers: {
      "X-Api-Key": "YOUR_API_KEY",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      customerId: "cust_12345",
      yourBalance: 48500,
      theirBalance: 49000,
      startingBalance: 50000,
      startingCheckpoint: "0xdef456...",
      startingCheckpointType: "itemsRoot",
    }),
  }
);

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

Python

python
import requests

response = requests.post(
    "https://balance-api.pacspace.io/api/v1/balance/compare",
    headers={
        "X-Api-Key": "YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "customerId": "cust_12345",
        "yourBalance": 48500,
        "theirBalance": 49000,
        "startingBalance": 50000,
        "startingCheckpoint": "0xdef456...",
        "startingCheckpointType": "itemsRoot",
    },
)

result = response.json()
print(result)

Response

json
{
  "success": true,
  "data": {
    "customerId": "cust_12345",
    "yourBalance": 48500,
    "theirBalance": 49000,
    "neutralBalance": 48500,
    "matchesYours": true,
    "matchesTheirs": false,
    "deltasVerified": 127,
    "discrepancyReport": {
      "amount": 500,
      "resolution": "Your balance is correct. The counterparty is overstated by 500.",
      "divergentParty": "theirs",
      "windowsToReview": [
        {
          "window": "2026-02",
          "netDelta": -1500,
          "deltasCount": 15,
          "timeRange": "2026-02-01T00:00:00Z to 2026-02-11T23:59:59Z"
        }
      ],
      "recommendation": "Share this report with the counterparty. The discrepancy originates in the February 2026 window."
    },
    "proof": {
      "itemsRoot": "0xabc789...",
      "latestCheckpoint": "0xabc789...",
      "windowSummaries": [
        {
          "window": "2026-02",
          "deltasCount": 15,
          "netDelta": -1500,
          "firstBlockTimestamp": "2026-02-01T10:15:00Z",
          "lastBlockTimestamp": "2026-02-11T22:45:00Z"
        }
      ]
    }
  }
}

Response Fields

FieldTypeDescription
customerIdstringThe customer account that was compared
yourBalancenumberThe balance you submitted
theirBalancenumberThe balance the counterparty submitted
neutralBalancenumberThe independently derived balance from verified deltas
matchesYoursbooleanWhether your submitted balance matches the neutral balance
matchesTheirsbooleanWhether the counterparty's balance matches the neutral balance
deltasVerifiednumberNumber of verified deltas included in the comparison
discrepancyReportobject | nullDetailed breakdown when a mismatch is found (see below)
proofobjectProof data covering the comparison (see below)

Discrepancy Report

Returns null when all three balances match (yours, theirs, and the neutral truth). Otherwise, contains a detailed breakdown:

FieldTypeDescription
amountnumberThe absolute difference between the two balances
resolutionstringHuman-readable explanation of the finding
divergentPartystringWhich side is incorrect: "yours", "theirs", or "both"
windowsToReviewarrayTime windows where the discrepancy originated
relevantWindowsarrayTop 5 most impactful windows for investigation, sorted by absolute net delta
recommendationstringSuggested next steps to resolve the discrepancy

When both parties agree with each other but both differ from the neutral truth, divergentParty is "both" with an explanation that both sides have drifted from the verified record.

Window to Review Object

FieldTypeDescription
windowstringTime window where the mismatch occurred
netDeltanumberThe net change derived from verified deltas
deltasCountnumberNumber of deltas in the window
timeRangestring | nullDate range of the window (null if no timestamps available)

Proof Object

FieldTypeDescription
itemsRootstringProof root covering all deltas used in the comparison
latestCheckpointstring | nullLatest checkpoint used in the comparison
windowSummariesarrayWindow-by-window summary of verified deltas

How It Works

  1. You submit both balances — your view and the counterparty's view, along with an agreed starting point.

  2. PacSpace derives the truth — Using only verified deltas, PacSpace computes the neutral balance independently of either party's records.

  3. You get a verdict — The response tells you exactly who matches, who diverges, when the discrepancy started, and what to do about it.

Tip: If both matchesYours and matchesTheirs are true, the balances agree and no discrepancyReport is returned. If both are false, both parties have drifted from the verified record.