Settle Sessions

When usage tracking is complete, stop the session and settle it to generate an invoice. Settlement creates a ledger entry and optionally generates an invoice for the final usage amount.


Stop Session

Stop a session and optionally settle it immediately.

Endpoint

POST
/v1/metered-billing/sessions/{session_id}/stop

Authorization: Bearer <ORVION_API_KEY> or X-API-Key: <ORVION_API_KEY>

Content-Type: application/json

Request Body

FieldTypeRequiredDescriptionExample
settleboolean
Optional
Whether to settle the session immediately (default: false)true

Example: cURL

cURL
# Stop without settling
curl -X POST "https://api.orvion.sh/v1/metered-billing/sessions/sess_abc123/stop" \
-H "Authorization: Bearer $ORVION_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"settle": false
}'
# Stop and settle immediately
curl -X POST "https://api.orvion.sh/v1/metered-billing/sessions/sess_abc123/stop" \
-H "Authorization: Bearer $ORVION_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"settle": true
}'

Example: Python SDK

Python
from orvion import OrvionClient
# Initialize client
orvion = OrvionClient(api_key="your_api_key")
# Get session
session = await orvion.usage.get_session("sess_abc123")
# Stop without settling
result = await session.stop(settle=False)
print(f"Session stopped: {result.session.status}")
# Or stop and settle immediately
result = await session.stop(settle=True)
if result.settlement:
print(f"Settled: ${result.settlement.settled_amount}")
print(f"Invoice ID: {result.settlement.invoice_id}")

Example: Node.js SDK

JavaScript
import { OrvionClient } from '@orvion/sdk';
// Initialize client
const orvion = new OrvionClient({ apiKey: 'your_api_key' });
// Get session
const session = await orvion.usage.getSession('sess_abc123');
// Stop without settling
const result = await session.stop({ settle: false });
console.log(`Session stopped: ${result.session.status}`);
// Or stop and settle immediately
const result2 = await session.stop({ settle: true });
if (result2.settlement) {
console.log(`Settled: $${result2.settlement.settledAmount}`);
console.log(`Invoice ID: ${result2.settlement.invoiceId}`);
}

Response Example

{
  "session": {
    "id": "sess_abc123",
    "status": "stopped",
    "customer_ref": "user_123",
    "usage": {
      "total_seconds": 1000,
      "total_amount": "2.50"
    },
    "stopped_at": "2025-01-15T11:00:00Z"
  },
  "settlement": {
    "settled_amount": "2.50",
    "invoice_id": "inv_xyz789",
    "already_settled": false
  }
}

Settle Session

Settle a stopped session to generate an invoice. Idempotent - safe to retry.

Endpoint

POST
/v1/metered-billing/sessions/{session_id}/settle

Authorization: Bearer <ORVION_API_KEY> or X-API-Key: <ORVION_API_KEY>

Example: cURL

cURL
curl -X POST "https://api.orvion.sh/v1/metered-billing/sessions/sess_abc123/settle" \
-H "Authorization: Bearer $ORVION_API_KEY"

Example: Python SDK

Python
from orvion import OrvionClient
# Initialize client
orvion = OrvionClient(api_key="your_api_key")
# Get session
session = await orvion.usage.get_session("sess_abc123")
# Settle the session
result = await session.settle()
print(f"Settled amount: ${result.settled_amount}")
print(f"Invoice ID: {result.invoice_id}")
print(f"Already settled: {result.already_settled}")

Example: Node.js SDK

JavaScript
import { OrvionClient } from '@orvion/sdk';
// Initialize client
const orvion = new OrvionClient({ apiKey: 'your_api_key' });
// Get session
const session = await orvion.usage.getSession('sess_abc123');
// Settle the session
const result = await session.settle();
console.log(`Settled amount: $${result.settledAmount}`);
console.log(`Invoice ID: ${result.invoiceId}`);
console.log(`Already settled: ${result.alreadySettled}`);

Response Example

{
  "settled_amount": "2.50",
  "invoice_id": "inv_xyz789",
  "already_settled": false
}

Settlement Flow

1. Session Active         2. Stop Session         3. Settle Session
   ┌─────────────┐          ┌─────────────┐          ┌─────────────┐
   │             │          │             │          │             │
   │ Status:     │          │ POST /stop  │          │ POST /settle│
   │ active      │          │             │          │             │
   │             │          │ Status:     │          │ Status:     │
   │ Usage:      │    ──▶   │ stopped     │    ──▶   │ settled     │
   │ 1000s      │          │             │          │             │
   │ $2.50      │          │ Usage:      │          │ Invoice:    │
   │             │          │ 1000s       │          │ inv_xyz789  │
   │             │          │ $2.50      │          │             │
   └─────────────┘          └─────────────┘          └─────────────┘

What Happens During Settlement

  1. Balance Deduction: The final usage amount is deducted from the customer's balance
  2. Ledger Entry: A debit entry is created in the balance ledger
  3. Invoice Generation: An invoice is created for the settled amount
  4. Session Update: Session status changes to settled and settled_at is set

Idempotency

Settlement is idempotent. If you call settle() multiple times:

  • The first call settles the session and generates an invoice
  • Subsequent calls return the same settlement result with already_settled: true
  • No duplicate invoices or ledger entries are created

Insufficient Balance

If the customer's balance is insufficient when settling:

Response (402 Payment Required)

{
  "detail": "Insufficient balance to settle session"
}

Handling

You can:

  1. Top up balance and retry settlement
  2. Allow negative balance by adjusting your balance service logic
  3. Stop session without settling and handle payment separately

Invoice Details

The generated invoice includes:

  • Customer reference: From the session
  • Amount: Settled amount from usage
  • Currency: From session pricing
  • Line items: Usage details (seconds, rate, total)
  • Metadata: Session metadata if provided

You can retrieve the invoice via the Invoices API:

invoice = await orvion.invoices.get("inv_xyz789")
print(f"Invoice amount: ${invoice.total_amount}")
print(f"Status: {invoice.status}")

Complete Example

from orvion import OrvionClient
from orvion.usage import UsagePricing, UsageCap

async def complete_metered_billing_flow():
    orvion = OrvionClient(api_key="your_api_key")
    
    # 1. Top up balance
    balance = await orvion.metered_billing.top_up_balance(
        customer_ref="user_123",
        currency="USD",
        amount="100.00"
    )
    print(f"Balance: ${balance.available_amount}")
    
    # 2. Create session
    session = await orvion.usage.create_session(
        customer_id="user_123",
        pricing=UsagePricing(
            currency="USD",
            unit="second",
            unit_price="0.0025"
        ),
        cap=UsageCap(amount="50.00")
    )
    print(f"Session created: {session.id}")
    
    # 3. Report usage (simulated)
    for i in range(10):
        result = await session.tick(seconds=10)
        if result.insufficient_balance or result.cap_reached:
            break
        print(f"Tick {i+1}: {result.session_status}")
    
    # 4. Stop and settle
    result = await session.stop(settle=True)
    if result.settlement:
        print(f"Settled: ${result.settlement.settled_amount}")
        print(f"Invoice: {result.settlement.invoice_id}")
    
    # 5. Check final balance
    balance = await orvion.metered_billing.get_balance(balance.id)
    print(f"Final balance: ${balance.available_amount}")

Important Notes

Session Status

  • active - Session is running, accepting ticks
  • stopped - Session stopped, not accepting ticks, not yet settled
  • settled - Session settled, invoice generated

Settlement Timing

You can settle:

  • Immediately when stopping: stop(settle=True)
  • Later after stopping: stop(settle=False) then settle()

Invoice Generation

Invoices are automatically created during settlement. The invoice:

  • References the session
  • Includes usage details
  • Can be retrieved via the Invoices API
  • Can be sent to customers via the Invoicing API

Error Responses

402 Payment Required

{
  "detail": "Insufficient balance to settle session"
}

404 Not Found

{
  "detail": "Session not found"
}

409 Conflict

{
  "detail": "Session must be stopped before settling"
}

Next Steps