Tutorial: events then ratings (ingestion first)
Goal: ingest an outcome event as a fact record. Downstream rating is typically asynchronous.
You will:
- Record an event (
POST /mgt/v1/events). - Optionally record a batch (
POST /mgt/v1/events/batch).
Prereqs
- Completed Verify installation and integration.
- A stable
principal_id.
Step 1: record one event
curl
Use the SDK for the simplest first pass.
TypeScript (SDK)
// TODO
Python (SDK)
import asyncio
import os
from vlunaai_sdk import (
VlunaAIConfig,
RequestContext,
ServiceClientOptions,
ServiceKeyCredentials,
create_service_client,
)
def env(name: str) -> str:
v = os.environ.get(name)
if not v:
raise RuntimeError(f"Missing env: {name}")
return v
async def main() -> None:
client = create_service_client(
ServiceClientOptions(
config=VlunaAIConfig(
base_url=os.environ.get('VLUNA_SERVICE_BASE_URL', 'https://api.us-east-1.vluna.ai/mgt/v1'),
realm_id=env('VLUNA_REALM_ID'),
),
service_key=ServiceKeyCredentials(
key_id=env('VLUNA_SERVICE_KEY_ID'),
secret=env('VLUNA_SERVICE_KEY_SECRET'),
),
)
)
try:
principal_id = 'customer_123'
ctx = RequestContext(principal_id=principal_id, idempotency_key='ik_event_0001')
resp = await client.record_billing_event(
body={
'semantic_kind': 'outcome',
'event_type': 'outcome.job_succeeded',
'occurred_at': '2026-01-10T00:00:00Z',
'payload': {'run_id': 'run_456'},
'labels': {'project': 'alpha'},
},
context=ctx,
)
print(resp.model_dump())
finally:
await client.close()
asyncio.run(main())
Verify:
- You receive
201 Createdon first write, or200 OKfor an idempotent replay.
Step 2: record a batch
curl
Use the SDK for the simplest first pass.
TypeScript (SDK)
// TODO
Python (SDK)
# TODO
Verify:
- You receive
207 Multi-Statuswith per-item results.
What this does not prove
Successful ingestion does not prove rating is complete. Rating is typically asynchronous and eventually consistent.
Next
- Outcome-based model and verification strategies: Outcome-based billing model (events then ratings)
- Reports: Operational reports