Tutorial: authorize then commit
Goal: wire the core runtime gate loop into one real code path.
You will:
- Authorize work (
POST /mgt/v1/gate/authorize) to obtain alease. - Execute the protected work.
- Commit usage (
POST /mgt/v1/gate/commits) with actual post-call usage. - If protected work fails or produces no usage, send no commit; the lease expires naturally.
Prereqs
- Completed Verify installation and integration.
- A stable
principal_idyou control (for example, an org id). - If your product is LLM- or agent-driven, read LLM integration first.
Step 1: choose identifiers
Use:
principal_id: a stable org/team/customer identifier.user_id: the stable runtime user identifier under that principal.feature_code: the feature you are gating (example:openai.gpt-4o).feature_family_code: optional grouping chosen by your packaging and entitlement model.lease: optional caller-owned lifecycle reference. Supply a stable one-time operation id when you already have one, or omit it and use the generated response value.budget: optional caller-owned Budget reference returned by Budget creation. It is not the internalbudget_id.quantity_minor: integer feature-level usage in minor units as a string.meters[]: optional meter-level breakdown when separate priced resources matter.
For LLM workloads:
- top-level
quantity_minorshould usually be total tokens - if input, output, or cached tokens price differently, also send
meters[]
Step 2: authorize
curl
Use the SDK for the simplest first pass.
TypeScript (SDK)
import {
createServiceClient,
type RequestContext,
} from '@vlunaai/sdk'
function env(name: string): string {
const value = process.env[name]
if (!value) {
throw new Error(`Missing env: ${name}`)
}
return value
}
async function main() {
const client = createServiceClient({
config: {
baseUrl: process.env.VLUNA_SERVICE_BASE_URL || 'https://us-central1.api.vluna.ai/mgt/v1',
realmId: env('VLUNA_REALM_ID'),
},
serviceKey: {
keyId: env('VLUNA_SERVICE_KEY_ID'),
secret: env('VLUNA_SERVICE_KEY_SECRET'),
},
errorMode: 'result',
})
try {
const principalId = 'customer_123'
const userId = 'user_456'
const ctx: RequestContext = {
principalId,
userId,
idempotencyKey: 'ik_authorize_0001',
}
const authz = await client.s2s.gate.authorize(
{
feature_code: 'openai.gpt-4o',
feature_family_code: 'llm.standard',
estimated_quantity_minor: '1200',
},
ctx,
)
console.log(authz)
} finally {
await client.close()
}
}
void main()
Python (SDK)
import asyncio
import os
from vlunaai 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://us-central1.api.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'
user_id = 'user_456'
ctx = RequestContext(principal_id=principal_id, user_id=user_id, idempotency_key='ik_authorize_0001')
authz = await client.authorize(
body={
'feature_code': 'openai.gpt-4o',
'feature_family_code': 'llm.standard',
'estimated_quantity_minor': '1200',
},
context=ctx,
)
print(authz.model_dump())
finally:
await client.close()
asyncio.run(main())
Verify:
- You receive an envelope with
data.lease. hintsmay be present. Log them.
Step 3: commit
At this point, execute the protected work and collect actual usage.
For LLM workloads, this usually means:
- make the model call
- wait until final usage is known
- use total tokens as top-level
quantity_minor - add
meters[]when you need separate input/output/cached pricing
curl
Use the SDK for the simplest first pass.
TypeScript (SDK)
import {
createServiceClient,
type RequestContext,
} from '@vlunaai/sdk'
function env(name: string): string {
const value = process.env[name]
if (!value) {
throw new Error(`Missing env: ${name}`)
}
return value
}
async function main() {
const client = createServiceClient({
config: {
baseUrl: process.env.VLUNA_SERVICE_BASE_URL || 'https://us-central1.api.vluna.ai/mgt/v1',
realmId: env('VLUNA_REALM_ID'),
},
serviceKey: {
keyId: env('VLUNA_SERVICE_KEY_ID'),
secret: env('VLUNA_SERVICE_KEY_SECRET'),
},
errorMode: 'result',
})
try {
const principalId = 'customer_123'
const userId = 'user_456'
const ctx: RequestContext = {
principalId,
userId,
}
const authz = await client.s2s.gate.authorize(
{
feature_code: 'openai.gpt-4o',
feature_family_code: 'llm.standard',
estimated_quantity_minor: '1200',
},
{
...ctx,
idempotencyKey: 'ik_authorize_0001',
},
)
const envelope = authz.data as { ok?: boolean; data?: { lease?: string } } | undefined
const lease = envelope?.data?.lease
if (!lease) {
throw new Error('authorize failed')
}
const totalTokens = '1200'
const commit = await client.s2s.gate.commit(
{
lease,
feature_code: 'openai.gpt-4o',
quantity_minor: totalTokens,
meters: [
{ meter_code: 'openai.gpt-4o.tokens.input', quantity_minor: '800' },
{ meter_code: 'openai.gpt-4o.tokens.output', quantity_minor: '400' },
],
labels: { request_id: 'r-1' },
},
{
...ctx,
idempotencyKey: 'ik_commit_0001',
},
)
console.log(commit)
} finally {
await client.close()
}
}
void main()
Python (SDK)
import asyncio
import os
from vlunaai 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://us-central1.api.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'
user_id = 'user_456'
ctx = RequestContext(principal_id=principal_id, user_id=user_id)
authz = await client.authorize(
body={
'feature_code': 'openai.gpt-4o',
'feature_family_code': 'llm.standard',
'estimated_quantity_minor': '1200',
},
context=ctx.model_copy(update={'idempotency_key': 'ik_authorize_0001'}),
)
if not authz.ok or not authz.data:
raise RuntimeError(f"authorize failed: {authz.model_dump()}")
commit = await client.commit(
body={
'lease': authz.data.lease,
'feature_code': 'openai.gpt-4o',
'quantity_minor': '1200',
'meters': [
{'meter_code': 'openai.gpt-4o.tokens.input', 'quantity_minor': '800'},
{'meter_code': 'openai.gpt-4o.tokens.output', 'quantity_minor': '400'},
],
'labels': {'request_id': 'r-1'},
},
context=ctx.model_copy(update={'idempotency_key': 'ik_commit_0001'}),
)
print(commit.model_dump())
finally:
await client.close()
asyncio.run(main())
Verify:
- Commit returns an envelope with
data.amount_xusd(it may be0depending on pricing). hintsmay be present. Treat them as machine-readable signals.
Step 4: failure needs no compensation call
Authorize records an admission attempt but does not reserve funds, quota, or another consumable resource. If protected work fails before usage is known, do not commit. The uncommitted lease expires according to its TTL. A failed operation does not refund authorize-time rate counting.
Troubleshoot
402: blocked by enforcement (funding, quota, or budget).409:Idempotency-Keyconflict (same key used with a different body).429: rate limit. Retry with backoff and stable idempotency keys for replays.422: validation failed (invalid identifiers, policy window issues, or feature/meter restrictions).
Next
- LLM and agent runtime patterns: LLM integration
- Feature and meter naming: Features and meters
- Identities and mapping rules: Identifiers and lifecycles
- Operational safety: Operational safety