API Reference

Complete REST API documentation for the Pactum platform.


Authentication

The API uses two authentication methods depending on the context:

MethodHeaderUsed ByEndpoints
Session Cookiepactum_session (HTTP-only, HMAC-signed)Dashboard UIKeys, Policies, Invoices, Settlement (manual), Usage summary
API KeyX-API-Key: pactum_<hex>Third-party apps/usage/track, /wallet/balance
Bearer TokenAuthorization: Bearer <CRON_SECRET>Settlement cron/settlement/cron
Wallet Signaturex-pactum-address + x-pactum-timestamp + x-pactum-signatureEnd-user wallets/wallet/balance

Usage Tracking

POST /api/v1/usage/track

Records a single usage event. This is the primary SDK endpoint called by third-party applications.

Auth: X-API-Key header

Request Body:

{
  "model": "gpt-4",
  "prompt_tokens": 150,
  "completion_tokens": 75,
  "prompt_price_per_token": 0.000005,
  "completion_price_per_token": 0.000015,
  "user_address": "0x1234...abcd",
  "idempotency_key": "req-abc-123",
  "metadata": {
    "app": "my-ai-app",
    "session_id": "sess-456"
  }
}
FieldTypeRequiredDescription
modelstringYesModel or endpoint identifier
prompt_tokensnumberNoNumber of input tokens
completion_tokensnumberNoNumber of output tokens
prompt_price_per_tokennumberNoPrice per input token (USDC)
completion_price_per_tokennumberNoPrice per output token (USDC)
user_addressstringYesEnd-user wallet address (0x...)
idempotency_keystringYesUnique key to prevent duplicate charges
metadataobjectNoArbitrary key-value data for tracking

Response (200):

{
  "recorded": true,
  "deduplicated": false,
  "event_id": "uuid-of-event",
  "cost": 0.001875
}

Response (200 — Deduplicated):

{
  "recorded": true,
  "deduplicated": true,
  "event_id": "uuid-of-existing-event",
  "cost": 0.001875
}

Error Responses:

StatusCondition
400Missing required fields or invalid user_address format
401Missing or invalid API key
402Insufficient funds in user's State Channel balance
403API key has been revoked
429Policy limit exceeded — daily or monthly spend limit reached
500Database or on-chain read error
503Billing misconfigured — PACTUM_CONTRACT_ADDRESS missing on the server (fail-closed)

[!NOTE] Cost is calculated as: (prompt_tokens × prompt_price_per_token) + (completion_tokens × completion_price_per_token)


GET /api/v1/usage/summary

Returns the current user's spend for the current UTC day and month, plus the active policy limits and remaining budget.

Auth: Session cookie

Response (200):

{
  "daily_spend": 0.0125,
  "monthly_spend": 0.34,
  "daily_limit": 100,
  "monthly_limit": 3000,
  "remaining_daily": 99.9875,
  "remaining_monthly": 2999.66,
  "total_events_today": 7
}

API Keys

GET /api/v1/keys

List all API keys for the authenticated user's project.

Auth: Session cookie

Response (200):

{
  "keys": [
    {
      "id": "uuid",
      "key_prefix": "pactum_a1b2c3d4",
      "name": "Production",
      "status": "active",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ]
}

POST /api/v1/keys

Generate a new API key.

Auth: Session cookie

Request Body:

{
  "name": "Production Key"
}

Response (201):

{
  "key": "pactum_a1b2c3d4e5f6...",
  "id": "uuid",
  "key_prefix": "pactum_a1b2c3d4",
  "name": "Production Key",
  "status": "active",
  "created_at": "2026-01-01T00:00:00Z"
}

[!CAUTION] The key field contains the full API key and is only returned once. Store it securely.


Policies

GET /api/v1/policies

Get the active spend policy for the user's project.

Auth: Session cookie

Response (200):

{
  "policy": {
    "id": "uuid",
    "project_id": "uuid",
    "spend_limit_daily": 100.0,
    "spend_limit_monthly": 3000.0,
    "allowlist": [],
    "status": "active"
  }
}

PUT /api/v1/policies

Create or update the spend policy.

Auth: Session cookie

Request Body:

{
  "spend_limit_daily": 50.0,
  "spend_limit_monthly": 1500.0,
  "allowlist": ["gpt-4", "claude-3"]
}

Response (200):

{
  "policy": { ... }
}

Invoices

GET /api/v1/invoices

List invoices for the user's project. Optionally filter by status.

Auth: Session cookie

Query Parameters:

ParameterTypeDescription
statusstringFilter by invoice status: draft, finalized, settling, settled, failed

Response (200):

{
  "invoices": [
    {
      "id": "uuid",
      "project_id": "uuid",
      "period_start": "2026-01-01T00:00:00Z",
      "period_end": "2026-01-01T23:59:59Z",
      "total_amount": 12.345678,
      "status": "draft",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ]
}

POST /api/v1/invoices

Generate a new invoice by aggregating usage events within a time period.

Auth: Session cookie

Request Body:

{
  "period": "daily"
}
FieldTypeDescription
periodstring"daily" (default) or "monthly"
period_startstringISO date — overrides period
period_endstringISO date — overrides period

Response (201):

{
  "invoice": {
    "id": "uuid",
    "project_id": "uuid",
    "period_start": "2026-01-01T00:00:00Z",
    "period_end": "2026-01-01T23:59:59Z",
    "total_amount": 12.345678,
    "status": "draft",
    "usage_events": [ ... ]
  }
}

Settlement

POST /api/v1/settlement/cron

Triggers a global batch settlement of all pending usage events. Aggregates costs per (user, merchant) pair in exact integer units, skips groups whose on-chain user balance is insufficient (reported in skipped instead of reverting the whole batch), and executes batchSettleUsage on the PactumBilling smart contract in chunks of at most 50 groups. Each settled event records its settled_tx_hash.

Auth: Authorization: Bearer <operator_token>

Response (200):

{
  "message": "Settlement successful",
  "settledGroups": 5,
  "settledEvents": 42,
  "txHashes": ["0xabc...def"],
  "skipped": [
    { "user": "0x...", "merchant": "0x...", "reason": "on-chain balance below pending usage" }
  ]
}

Error Responses:

StatusCondition
401Invalid or missing operator token
500Contract call failed or missing configuration

POST /api/v1/settlement/manual

Same settlement engine as the cron endpoint, but scoped to the logged-in user's own projects — a dashboard user can only settle events belonging to their API keys, never other users'.

Auth: Session cookie

Response (200): same shape as /api/v1/settlement/cron.

Error Responses:

StatusCondition
401Not logged in
404User has no project
500Contract call failed

Wallet Balance

GET /api/v1/wallet/balance

Returns the total pending off-chain usage for a given address — used by wallet UIs to display the available balance, and by integrators for pre-flight checks. Authenticated access only (the numeric amount is not served to anonymous callers).

Auth — one of:

WhoHowScope
Third-party appX-API-Key headerPending usage of the address scoped to that key's own project
End-user walletx-pactum-address + x-pactum-timestamp + x-pactum-signature — a personal_sign of Pactum: verify wallet ownership\nAddress: <address>\nTimestamp: <ms> (±10 min)Full pending usage for that address
Dashboard sessionpactum_session cookieScoped to the logged-in user's projects

Query Parameters:

ParameterTypeRequiredDescription
addressstringYesUser wallet address, 0x + 40 hex

Response (200):

{
  "pendingUsage": 0.004325
}

Response (401): missing/invalid credentials for all three paths.

[!NOTE] Available balance = On-Chain Balance (userBalances) − pendingUsage. Read the on-chain half from the contract directly — see Contract Integration.


Receipts

GET /api/v1/receipts/:id

Retrieve the settlement receipt for a specific invoice, including the on-chain transaction hash.

Auth: Session cookie

Response (200):

{
  "receipt": {
    "invoice_id": "uuid",
    "tx_hash": "0xabc...def",
    "chain": "arc-testnet",
    "amount": 12.345678,
    "currency": "USDC",
    "status": "confirmed",
    "settled_at": "2026-01-01T12:00:00Z"
  }
}