Billing & Metering
Modei uses bilateral metering, both parties hold signed consumption attestations for every transaction. Settlement aggregates these with cryptographic verification and bigint arithmetic (no floats).
Consumption Attestations
Every billable action produces a consumption attestation (CA), a signed record that both the operator and consumer hold. CAs contain:
{
"id": "ca_01HXYZ...",
"passport_id": "pass_01HABC...",
"gate_id": "gate_acme-travel",
"action": "flights:search",
"outcome": "success",
"quantity": 1,
"unit_price_cents": 2,
"total_cost_cents": 2,
"platform_fee_cents": 1,
"catalog_version": 3,
"catalog_content_hash": "sha256:abc123...",
"agent_pop": {
"signature": "base64url...",
"public_key": "base64url...",
"timestamp": 1740399000000,
"nonce": "random-uuid",
"catalog_content_hash": "sha256:abc123...",
"request_payload_hash": "sha256:def456..."
},
"issued_at": "2026-02-24T14:30:00Z",
"signature": "base64url..."
}Recording Consumption
Call POST /api/consume to record service usage. This is typically called by the gate automatically after a allow decision when commerce constraints are present.
curl -X POST https://modei.ai/api/v1/consume \
-H "Authorization: Bearer mod_your_key" \
-H "Content-Type: application/json" \
-d '{
"passport_id": "pass_01HABC...",
"gate_id": "gate_acme-travel",
"action": "flights:book",
"outcome": "success",
"quantity": 1,
"agent_pop": {
"signature": "base64url...",
"public_key": "base64url...",
"timestamp": 1740399000000,
"nonce": "unique-nonce-here",
"catalog_content_hash": "sha256:abc123...",
"request_payload_hash": "sha256:def456..."
},
"request_payload_hash": "sha256:def456...",
"response_payload_hash": "sha256:ghi789..."
}'Proof-of-Possession (PoP)
For billable actions, agents must sign requests with their Ed25519 (an industry-standard elliptic curve signing algorithm) key. The PoP proves the agent actually made the request (prevents replay attacks).
Python SDK helpers for commerce are coming soon. Use the REST API below until modei.commerce ships.The PoP includes: Ed25519 signature, public key, timestamp (freshness: 300s window), nonce (replay protection), catalog content hash, and request payload hash.
Settlement Engine
Settlement aggregates consumption attestations for a billing period:
POST /api/billing
Authorization: Bearer mod_your_key
{
"gate_id": "gate_acme-travel",
"period_type": "monthly",
"period_start": "2026-02-01T00:00:00Z",
"period_end": "2026-02-28T23:59:59Z"
}
# Response:
{
"settlement_id": "set_01HXYZ...",
"status": "pending",
"total_cost_cents": 124500,
"total_platform_fee_cents": 3113,
"total_transactions": 12345,
"permission_breakdown": {
"flights:search": { "count": 12000, "total_cents": 24000 },
"flights:book": { "count": 345, "total_cents": 100500 }
},
"outcome_breakdown": {
"success": 12300,
"error": 25,
"timeout": 20
},
"content_hash": "sha256:xyz789..."
}Settlement flow:
Settlement Status Machine
pending → invoiced → paid
│ └→ disputed → invoiced → paid
└→ void └→ void- pending, created, not yet invoiced
- invoiced, invoice sent, awaiting payment
- paid, final, cannot be changed
- disputed, under dispute review
- void, voided, final
Only status and status_changed_at can change after creation, all other columns are frozen by database trigger.
PATCH /api/billing/{settlement_id}/status
{ "new_status": "invoiced" }SLA Compliance
Track compliance against catalog SLA guarantees across any time period:
GET /api/gates/gate_acme-travel/sla?period_start=2026-02-01T00:00:00Z&period_end=2026-02-28T23:59:59Z
# Response:
{
"overall_compliant": true,
"permissions": {
"flights:search": {
"contracted_uptime_bp": 9990,
"actual_uptime_bp": 9995,
"compliant": true,
"success": 12000,
"error": 25,
"timeout": 5
}
}
}Financial Precision
Bigint arithmetic
All amounts are stored and computed as bigint in cents. No floating-point errors anywhere in the pipeline.
Ceiling division for fees
Platform fees are computed with ceiling division: never undercharges, always deterministic.
Nonce replay protection
UNIQUE constraint on (nonce, passport_id, gate_id). Each request can only be billed once.
Immutable summaries
Settlement summaries cannot be updated or deleted, DB triggers enforce this at the data layer.
Related
- Permission Catalogs, Define pricing and SLA terms that drive billing.
- Anti-Bait-and-Switch, Catalog pinning ensures billing terms don't change.
- Commerce API Reference, Full billing and consume endpoint docs.