{"openapi":"3.1.0","info":{"title":"Revenium Metering API","description":"Revenium Metering API","contact":{"name":"Revenium","url":"https://revenium.io","email":"info@revenium.io"},"version":"2.0.0"},"externalDocs":{"description":"Revenium Metering Documentation","url":"https://docs.revenium.io"},"servers":[{"url":"https://api.revenium.ai/meter/","description":"Revenium Metering API (Production)"}],"tags":[{"name":"API Metering","description":"API Metering Operations"},{"name":"AI Metering","description":"AI Metering Operations"},{"name":"AI Video Metering","description":"Metering operations for video AI workloads (generation, editing, processing)"},{"name":"AI Audio Metering","description":"Metering operations for audio AI workloads (transcription, TTS, translation)"},{"name":"OTLP","description":"OpenTelemetry Protocol Metering Operations"},{"name":"AI Image Metering","description":"Metering operations for image AI workloads (generation, editing, variations)"},{"name":"Event Metering","description":"Event Metering Operations"},{"name":"Tool Metering","description":"Tool/Function Call Metering Operations"}],"paths":{"/v2/tool/events":{"post":{"tags":["Tool Metering"],"summary":"Meter Tool Event","description":"Submit tool/function call metadata for metering and billing purposes.","operationId":"meter_tool_event","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"description":"Tool event metadata including tool ID, operation, duration, and attribution","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolEventMetadataResource"},"examples":{"Basic Tool Event":{"summary":"Minimal required fields for tool event metering","description":"Basic tool event with only required fields","value":{"toolId":"web_scraper","operation":"fetch","durationMs":1234,"success":true,"timestamp":"2025-01-15T12:00:00Z"}},"Complete Tool Event":{"summary":"Full tool event with all optional fields","description":"Comprehensive tool event metering with attribution and cost tracking","value":{"transactionId":"txn-tool-002","toolId":"firecrawl","operation":"scrape","durationMs":2500,"success":true,"costUsd":0.005,"timestamp":"2025-01-15T12:00:00Z","agent":"research-assistant","product":"customer-portal","organizationName":"org-123","workflowId":"wf-456","traceId":"trace-789","usageMetadata":{"pages":5,"data_mb":2.3}}},"Failed Tool Event":{"summary":"Tool event with error information","description":"Tool event that failed with error message","value":{"toolId":"github_api","operation":"fetch_repo","durationMs":500,"success":false,"errorMessage":"Repository not found","timestamp":"2025-01-15T12:00:00Z","agent":"code-analyzer"}}}}},"required":true},"responses":{"201":{"description":"Tool event successfully metered","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"},"examples":{"Metering Success":{"summary":"Tool event successfully metered","description":"Metering Success","value":{"resourceType":"metered-event","label":"metered-event","created":"2025-01-15T12:00:04.838Z","updated":"2025-01-15T12:00:04.838Z","id":"57edfb66-8657-4184-ab8a-80b389b3a48e","signature":"df53675c5de8445f4a15d6cd5614c56b37b0105bf2f78e181e1d14189127c9c2"}}}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/otlp/v1/traces":{"post":{"tags":["OTLP"],"summary":"Accept OTLP traces","description":"Receive OTLP trace spans containing AI completion data. Accepts both application/json (shown below) and application/x-protobuf (used by default by the standard OpenTelemetry SDKs; refer to the OTLP spec). Supported providers: OpenTelemetry GenAI semantic conventions. Provider is auto-detected from resource attributes.","operationId":"otlp_traces","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPTracesPayload"}}},"required":true},"responses":{"200":{"description":"Returns the OTLP processing response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPResponse"}}}},"400":{"description":"Invalid OTLP data or unsupported provider","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Conflict","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"x-api-key":[]}]}},"/v2/otlp/v1/metrics":{"post":{"tags":["OTLP"],"summary":"Accept OTLP metrics","description":"Receive OTLP metrics containing AI usage data (tokens, costs). Accepts both application/json (shown below) and application/x-protobuf (used by default by the standard OpenTelemetry SDKs; refer to the OTLP spec). Provider is auto-detected from resource attributes. Note: Claude Code metrics are intentionally not processed and produce no records — Claude Code's per-call cost and token data is captured via the /v1/logs endpoint instead. Sending Claude Code metric payloads here is harmless but yields processedEvents=0.","operationId":"otlp_metrics","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPMetricsPayload"}}},"required":true},"responses":{"200":{"description":"Returns the OTLP processing response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPResponse"}}}},"400":{"description":"Invalid OTLP data or unsupported provider","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Conflict","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"x-api-key":[]}]}},"/v2/otlp/v1/logs":{"post":{"tags":["OTLP"],"summary":"Accept OTLP logs","description":"Receive OTLP log events containing AI completion metrics. Accepts both application/json (shown below) and application/x-protobuf (used by default by the standard OpenTelemetry SDKs; refer to the OTLP spec). Supported providers: Claude Code. Provider is auto-detected from resource attributes.","operationId":"otlp_logs","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPLogsPayload"}}},"required":true},"responses":{"200":{"description":"Returns the OTLP processing response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPResponse"}}}},"400":{"description":"Invalid OTLP data or unsupported provider","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Conflict","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"x-api-key":[]}]}},"/v2/otlp/":{"post":{"tags":["OTLP"],"summary":"Accept unified OTLP data","description":"Receive OTLP data containing logs and/or metrics in a single request. This endpoint handles SDKs (like Gemini CLI) that don't append standard /v1/logs or /v1/metrics suffixes.","operationId":"otlp_unified","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPUnifiedPayload"}}},"required":true},"responses":{"200":{"description":"Returns the OTLP processing response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPResponse"}}}},"400":{"description":"Invalid OTLP data or unsupported provider","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Conflict","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"x-api-key":[]}]}},"/v2/otlp":{"post":{"tags":["OTLP"],"summary":"Accept unified OTLP data","description":"Receive OTLP data containing logs and/or metrics in a single request. This endpoint handles SDKs (like Gemini CLI) that don't append standard /v1/logs or /v1/metrics suffixes.","operationId":"otlp_unified_1","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPUnifiedPayload"}}},"required":true},"responses":{"200":{"description":"Returns the OTLP processing response.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OTLPResponse"}}}},"400":{"description":"Invalid OTLP data or unsupported provider","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"401":{"description":"Unauthorized","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Not Found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"description":"Conflict","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"422":{"description":"Unprocessable Content","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}}},"security":[{"x-api-key":[]}]}},"/v2/events":{"post":{"tags":["Event Metering"],"summary":"Meter an event","description":"Submit a generic metering event with a flexible payload structure. Use this endpoint to meter custom events that you wish to track in Revenium. The payload should contain any key-value pairs representing metrics to track or rate for usage-based revenue calculation.  The key values sent here will be created as 'metering elements' if they do not already exist, and rated according to pricing definitions for the relevant metering element on a product if they do.","operationId":"meter_event","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringEvent"}}},"required":true},"responses":{"201":{"description":"Event successfully metered and queued for processing","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Unprocessable entity","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/apis/responses":{"post":{"tags":["API Metering"],"summary":"Meter an API response","description":"Meter an API response","operationId":"meter_api_response","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIResponseMetadataResource"}}},"required":true},"responses":{"201":{"description":"Returns the created metering response object.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Unprocessable entity","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/apis/requests":{"post":{"tags":["API Metering"],"summary":"Meter an API request","description":"Meter an API request","operationId":"meter_api_request","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/APIRequestMetadataResource"}}},"required":true},"responses":{"201":{"description":"Returns the created metering response object.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Unprocessable entity","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/ai/video":{"post":{"tags":["AI Video Metering"],"summary":"Meter AI Video Operation","description":"Submit video generation/editing metadata for metering and billing purposes.","operationId":"meter_ai_video","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"description":"AI video operation metadata including duration, credits, and video-specific attributes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIVideoMetadataResource"},"examples":{"Video Generation (RunwayML)":{"summary":"Video generation with credit-based billing","description":"Example of generating a video using RunwayML Gen-3","value":{"transactionId":"video-txn-001","model":"gen-3-alpha","provider":"RunwayML","operationType":"VIDEO","operationSubtype":"generation","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:06:05Z","requestDuration":120000,"durationSeconds":10,"resolution":"1920x1080","fps":24,"creditsConsumed":100,"creditRate":0.05,"videoJobId":"runway-job-xyz789","style":"cinematic"}},"Video Generation (Duration-based)":{"summary":"Video generation with duration-based billing","description":"Example of generating a video with per-second pricing","value":{"transactionId":"video-txn-002","model":"pika-1.0","provider":"Pika","operationType":"VIDEO","operationSubtype":"generation","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:05:35Z","requestDuration":90000,"durationSeconds":5,"resolution":"1280x720","fps":30,"aspectRatio":"16:9","quality":"high"}},"Video Upscaling":{"summary":"Video upscaling operation","description":"Example of upscaling a video to higher resolution","value":{"transactionId":"video-txn-003","model":"topaz-video-ai","provider":"Topaz","operationType":"VIDEO","operationSubtype":"upscale","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:14:05Z","requestDuration":600000,"durationSeconds":300,"fps":24,"resolution":"3840x2160"}}}}},"required":true},"responses":{"201":{"description":"Video operation successfully metered","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"},"examples":{"Metering Success":{"summary":"Video operation successfully metered","description":"Metering Success","value":{"resourceType":"metered-event","label":"metered-video-event","created":"2025-03-02T15:06:05.838Z","updated":"2025-03-02T15:06:05.838Z","id":"68fec677-9768-5295-bc9b-91c49ac4b59f","signature":"b2c3d4e5f6g7..."}}}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Validation failed - missing required video fields","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/ai/images":{"post":{"tags":["AI Image Metering"],"summary":"Meter AI Image Operation","description":"Submit image generation/editing metadata for metering and billing purposes.","operationId":"meter_ai_images","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"description":"AI image operation metadata including image counts, resolution, and image-specific attributes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIImageMetadataResource"},"examples":{"Image Generation (DALL-E 3)":{"summary":"High-quality image generation","description":"Example of generating HD images using DALL-E 3","value":{"transactionId":"img-txn-001","model":"dall-e-3","provider":"OpenAI","operationType":"IMAGE","operationSubtype":"generation","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:20Z","requestDuration":15000,"requestedImageCount":1,"actualImageCount":1,"resolution":"1024x1024","quality":"hd","style":"vivid"}},"Image Generation (DALL-E 2 Batch)":{"summary":"Multiple image generation","description":"Example of generating multiple images using DALL-E 2","value":{"transactionId":"img-txn-002","model":"dall-e-2","provider":"OpenAI","operationType":"IMAGE","operationSubtype":"generation","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:25Z","requestDuration":20000,"requestedImageCount":4,"actualImageCount":4,"resolution":"512x512","quality":"standard"}},"Image Edit/Inpaint":{"summary":"Image editing with mask","description":"Example of editing an existing image with inpainting","value":{"transactionId":"img-txn-003","model":"dall-e-2","provider":"OpenAI","operationType":"IMAGE","operationSubtype":"edit","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:18Z","requestDuration":13000,"requestedImageCount":1,"actualImageCount":1,"resolution":"1024x1024"}},"Image Variation":{"summary":"Generate variations of an image","description":"Example of creating variations of an existing image","value":{"transactionId":"img-txn-004","model":"dall-e-2","provider":"OpenAI","operationType":"IMAGE","operationSubtype":"variation","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:22Z","requestDuration":17000,"requestedImageCount":3,"actualImageCount":3,"resolution":"1024x1024"}}}}},"required":true},"responses":{"201":{"description":"Image operation successfully metered","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"},"examples":{"Metering Success":{"summary":"Image operation successfully metered","description":"Metering Success","value":{"resourceType":"metered-event","label":"metered-image-event","created":"2025-03-02T15:04:20.838Z","updated":"2025-03-02T15:04:20.838Z","id":"79gfd788-a879-6306-cd0c-a2d5abd5c60g","signature":"c3d4e5f6g7h8..."}}}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Validation failed - missing required image fields","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/ai/completions":{"post":{"tags":["AI Metering"],"summary":"Meter AI Completion","description":"Submit AI completion metadata for metering and billing purposes.","operationId":"meter_ai_completion","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"description":"AI completion metadata including token counts, costs, and timing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AICompletionMetadataResource"},"examples":{"Basic AI Completion":{"summary":"Minimal required fields for AI completion metering","description":"Basic AI completion with only required fields for token tracking","value":{"transactionId":"txn-test-001","model":"gpt-4","inputTokenCount":100,"outputTokenCount":150,"totalTokenCount":250,"stopReason":"END","requestTime":"2025-10-17T17:35:00Z","completionStartTime":"2025-10-17T17:35:00Z","responseTime":"2025-10-17T17:35:02Z","requestDuration":2000,"provider":"OpenAI"}},"Complete AI Completion":{"summary":"Full AI completion with all optional fields","description":"Comprehensive AI completion metering including costs, caching, and performance metrics","value":{"transactionId":"txn-test-002","traceId":"trace-456","model":"gpt-4-turbo","responseQualityScore":0.9,"modelSource":"OPENAI","inputTokenCount":75,"outputTokenCount":125,"reasoningTokenCount":50,"cacheCreationTokenCount":25,"cacheReadTokenCount":10,"totalTokenCount":285,"stopReason":"END","inputTokenCost":0.08,"outputTokenCost":0.12,"cacheCreationTokenCost":0.02,"cacheReadTokenCost":0.01,"totalCost":0.23,"costType":"AI","requestTime":"2025-10-17T17:35:00Z","completionStartTime":"2025-10-17T17:35:00Z","timeToFirstToken":250,"isStreamed":true,"responseTime":"2025-10-17T17:35:03Z","requestDuration":3000,"provider":"OpenAI","temperature":0.7,"organizationName":"org-123","subscriptionId":"sub-456","productName":"product-789"}}}}},"required":true},"responses":{"201":{"description":"AI completion successfully metered","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"},"examples":{"Metering Success":{"summary":"AI completion successfully metered","description":"Metering Success","value":{"resourceType":"metered-event","label":"metered-event","created":"2025-10-17T17:53:04.838Z","updated":"2025-10-17T17:53:04.838Z","id":"57edfb66-8657-4184-ab8a-80b389b3a48e","signature":"df53675c5de8445f4a15d6cd5614c56b37b0105bf2f78e181e1d14189127c9c2","transactionId":"txn-test-001"}}}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Unprocessable entity","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}},"/v2/ai/audio":{"post":{"tags":["AI Audio Metering"],"summary":"Meter AI Audio Operation","description":"Submit audio operation metadata (transcription, TTS, translation, real-time audio) for metering and billing purposes.","operationId":"meter_ai_audio","parameters":[{"name":"Idempotency-Key","in":"header","description":"Optional Stripe-style retry-safety key. If present, the response (status + body) is cached keyed by (tenant, key). Identical retries replay the cached response; body mismatch returns 409 idempotency_key_mismatch; a concurrent in-flight call returns 409 idempotency_key_in_progress with Retry-After: 1. Must be 1-255 printable ASCII characters; UUID v4 recommended. See https://docs.revenium.io/integrations/idempotency for full behavior.","schema":{"type":"string","maxLength":255,"minLength":1,"pattern":"^[!-~]+$"}}],"requestBody":{"description":"AI audio operation metadata including duration, character count, and audio-specific attributes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIAudioMetadataResource"},"examples":{"Audio Transcription (Whisper)":{"summary":"Transcription operation with duration-based billing","description":"Example of transcribing an audio file using OpenAI Whisper","value":{"transactionId":"audio-txn-001","model":"whisper-1","provider":"OpenAI","operationType":"AUDIO","operationSubtype":"transcription","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:15Z","requestDuration":10000,"durationSeconds":125.5,"language":"en","audioFormat":"mp3","sampleRate":44100}},"Text-to-Speech (TTS)":{"summary":"TTS operation with character-based billing","description":"Example of generating speech from text using OpenAI TTS","value":{"transactionId":"tts-txn-001","model":"tts-1-hd","provider":"OpenAI","operationType":"AUDIO","operationSubtype":"speech","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:04:08Z","requestDuration":3000,"characterCount":5000,"voice":"alloy","audioFormat":"mp3","quality":"hd"}},"Real-time Audio (GPT-4o)":{"summary":"Real-time audio operation with audio token billing","description":"Example of real-time audio processing using GPT-4o Realtime API","value":{"transactionId":"realtime-txn-001","model":"gpt-4o-realtime-preview","provider":"OpenAI","operationType":"AUDIO","operationSubtype":"realtime","requestTime":"2025-03-02T15:04:05Z","responseTime":"2025-03-02T15:05:05Z","requestDuration":60000,"inputAudioTokenCount":1500,"outputAudioTokenCount":2000,"inputTokenCount":100,"outputTokenCount":150,"isRealtime":true}}}}},"required":true},"responses":{"201":{"description":"Audio operation successfully metered","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringResponseResource"},"examples":{"Metering Success":{"summary":"Audio operation successfully metered","description":"Metering Success","value":{"resourceType":"metered-event","label":"metered-audio-event","created":"2025-03-02T15:04:15.838Z","updated":"2025-03-02T15:04:15.838Z","id":"57edfb66-8657-4184-ab8a-80b389b3a48e","signature":"a1b2c3d4e5f6..."}}}}}},"400":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyBadRequest"},"401":{"description":"Unauthorized - Authentication required","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"403":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/MeteringInsufficientScope"},"404":{"description":"Resource not found","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"409":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyConflict"},"413":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyPayloadTooLarge"},"422":{"description":"Validation failed - missing required audio fields","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"429":{"description":"Too Many Requests","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"*/*":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"500":{"description":"Internal server error","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"503":{"headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"}},"$ref":"#/components/responses/IdempotencyStoreUnavailable"}},"security":[{"x-api-key":[]}]}}},"components":{"schemas":{"ApiError":{"type":"object","description":"Error response from the API","properties":{"timestamp":{"type":"string","description":"The time the error occurred in ISO format","example":"2025-05-28T14:30:00Z"},"status":{"type":"integer","format":"int32","description":"The HTTP status code","example":400},"error":{"type":"string","description":"The HTTP status reason phrase","example":"Bad Request"},"message":{"type":["string","null"],"description":"The error message","example":"Validation failed for one or more fields"},"path":{"type":"string","description":"The request URI","example":"/api/v2/resource"},"details":{"type":"object","additionalProperties":{"type":"string"},"description":"Additional error details","example":{"field":"error message"}},"errors":{"type":["array","null"],"description":"Structured per-error entries for response shapes that need machine-readable error codes (e.g. strict ingestion mode 422 responses). Omitted from existing handlers for backward compatibility.","items":{"$ref":"#/components/schemas/StructuredError"}},"docsUrl":{"type":["string","null"],"description":"Link to documentation explaining the error and remediation steps.","example":"https://docs.revenium.io/ai/customer-and-subscriber-management/strict-ingestion-mode"}}},"StructuredError":{"type":"object","description":"Structured per-error entry with a stable code, optional single-field reference, and remediation guidance","properties":{"code":{"type":"string","description":"Stable error code. Strict ingestion responses use values from `StrictIngestionErrorCode`; future error vocabularies (other 422s) may emit their own stable strings here.","example":"PRODUCT_NOT_FOUND"},"field":{"type":["string","null"],"description":"The single input field this error refers to","example":"productId"},"value":{"type":["string","null"],"description":"The offending value, if applicable","example":"prd_xyz"},"message":{"type":"string","description":"Human-readable description of the error"},"resolution":{"type":"string","description":"Suggested remediation the caller can apply"}}},"ToolEventMetadataResource":{"type":"object","description":"The tool event metadata","properties":{"transactionId":{"type":["string","null"],"description":"Unique identifier for this tool call transaction","example":"txn-tool-001"},"toolId":{"type":"string","description":"Identifier of the tool being called","example":"firecrawl","minLength":1},"operation":{"type":["string","null"],"description":"The specific operation being performed by the tool","example":"scrape"},"durationMs":{"type":"integer","format":"int64","description":"Duration of the tool call in milliseconds","example":1234},"success":{"type":"boolean","description":"Whether the tool call was successful","example":true},"errorMessage":{"type":["string","null"],"description":"Error message if the tool call failed","example":"Connection timeout"},"costUsd":{"type":["number","null"],"format":"double","description":"Cost of the tool call in USD. When provided, this value overrides the tool's configured pricing and is used directly as the charge. When omitted, the charge is computed from the tool's pricing configuration (PlanElement unitAmount or Tier unitAmount).","example":0.001},"timestamp":{"type":"string","description":"ISO 8601 timestamp of when the tool call occurred","example":"2025-01-15T12:00:00Z","minLength":1},"agent":{"type":["string","null"],"description":"Name or identifier of the AI agent making the tool call","example":"customer-support-agent"},"organizationName":{"type":["string","null"],"description":"The name of the organization from your system for multi-tenant tracking","example":"org-123"},"productName":{"type":["string","null"],"description":"The name of the product or application from your system for attribution","example":"customer-portal"},"subscriberCredential":{"type":["string","null"],"description":"Subscriber or customer credential for billing attribution","example":"sub-456"},"workflowId":{"type":["string","null"],"description":"Workflow identifier for multi-step process tracking","example":"wf-789"},"traceId":{"type":["string","null"],"description":"Trace ID for distributed tracing correlation","example":"trace-abc"},"usageMetadata":{"type":["object","null"],"additionalProperties":{},"description":"Additional usage metadata as key-value pairs","example":{"pages":5,"data_mb":2.3}}},"required":["timestamp","toolId"]},"EnforcementDirective":{"type":"object","description":"Enforcement directive included when cost controls are triggered","properties":{"action":{"type":"string","description":"Enforcement action applied by the cost control","example":"BLOCK"},"ruleName":{"type":["string","null"],"description":"Name of the cost control that triggered this directive","example":"Monthly AI spend limit"},"message":{"type":["string","null"],"description":"Human-readable message describing the enforcement","example":"Budget warning: Monthly AI spend limit"}}},"MeteringResponseResource":{"type":"object","description":"Metering response resource details for the metering API, providing metadata about response creation and validation.","properties":{"resourceType":{"type":"string","description":"Type of the metered object. Varies by endpoint: 'metered-event' for AI completions, 'metered.api.request' for API requests, 'metered.api.response' for API responses, 'meter.event' for generic events.","example":"metered-event"},"label":{"type":"string","description":"A descriptive label for the metering response, typically matching the resourceType value","example":"metered-event"},"created":{"type":["string","null"],"description":"ISO8601 formatted timestamp when the response was created","example":"2025-03-02T15:04:05Z"},"updated":{"type":["string","null"],"description":"ISO8601 formatted timestamp when the response was last updated","example":"2025-03-02T15:04:06Z"},"id":{"type":"string","description":"Unique identifier for the metering response","example":"abc123"},"signature":{"type":"string","description":"Signature used for validating the response data","example":"signature123"},"transactionId":{"type":["string","null"],"description":"Transaction identifier accepted for this metering event. For AI completion metering, this echoes the caller-supplied transactionId/spanId or the UUID generated by Revenium when omitted.","example":"123e4567-e89b-12d3-a456-426614174000"},"enforcement":{"oneOf":[{"$ref":"#/components/schemas/EnforcementDirective"},{"type":"null"}]},"_links":{"$ref":"#/components/schemas/Links"}},"required":["id","label","resourceType","signature"]},"OTLPAnyValue":{"type":"object","description":"OTLP any value - supports multiple value types","properties":{"stringValue":{"type":["string","null"]},"boolValue":{"type":["boolean","null"]},"intValue":{"type":["integer","null"],"format":"int64"},"doubleValue":{"type":["number","null"],"format":"double"},"arrayValue":{"oneOf":[{"$ref":"#/components/schemas/OTLPArrayValue"},{"type":"null"}]},"kvlistValue":{"oneOf":[{"$ref":"#/components/schemas/OTLPKvlistValue"},{"type":"null"}]},"bytesValue":{"type":["string","null"]}}},"OTLPArrayValue":{"type":"object","description":"OTLP array value","properties":{"values":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPAnyValue"}}}},"OTLPKeyValue":{"type":"object","description":"OTLP key-value pair","properties":{"key":{"type":"string"},"value":{"$ref":"#/components/schemas/OTLPAnyValue"}}},"OTLPKvlistValue":{"type":"object","description":"OTLP key-value list","properties":{"values":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPKeyValue"}}}},"OTLPResource":{"type":"object","description":"OTLP resource containing attributes","properties":{"attributes":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPKeyValue"}}}},"OTLPResourceSpans":{"type":"object","description":"Resource spans — groups scope spans under a shared resource","properties":{"resource":{"oneOf":[{"$ref":"#/components/schemas/OTLPResource"},{"type":"null"}]},"scopeSpans":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPScopeSpans"}},"schemaUrl":{"type":["string","null"]}}},"OTLPScope":{"type":"object","description":"Instrumentation scope","properties":{"name":{"type":["string","null"]},"version":{"type":["string","null"]}}},"OTLPScopeSpans":{"type":"object","description":"Scope spans — groups spans from the same instrumentation scope","properties":{"scope":{"oneOf":[{"$ref":"#/components/schemas/OTLPScope"},{"type":"null"}]},"spans":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPSpan"}},"schemaUrl":{"type":["string","null"]}}},"OTLPSpan":{"type":"object","description":"Individual OTLP span representing a unit of work","properties":{"traceId":{"type":["string","null"]},"spanId":{"type":["string","null"]},"parentSpanId":{"type":["string","null"]},"name":{"type":["string","null"]},"kind":{"type":["integer","null"],"format":"int32"},"startTimeUnixNano":{"type":["string","null"]},"endTimeUnixNano":{"type":["string","null"]},"attributes":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPKeyValue"}},"status":{"oneOf":[{"$ref":"#/components/schemas/OTLPSpanStatus"},{"type":"null"}]},"droppedAttributesCount":{"type":["integer","null"],"format":"int32"}}},"OTLPSpanStatus":{"type":"object","description":"Span status code and message","properties":{"code":{"type":["integer","null"],"format":"int32"},"message":{"type":["string","null"]}}},"OTLPTracesPayload":{"type":"object","description":"OTLP traces payload in JSON format","properties":{"resourceSpans":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceSpans"}}}},"OTLPResponse":{"type":"object","description":"Response for OTLP processing","properties":{"id":{"type":"string"},"resourceType":{"type":"string"},"processedEvents":{"type":"integer","format":"int32"},"failedEvents":{"type":"integer","format":"int32"},"created":{"type":"string"}}},"OTLPGauge":{"type":"object","description":"Gauge metric","properties":{"dataPoints":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPNumberDataPoint"}}}},"OTLPMetric":{"type":"object","description":"Individual metric","properties":{"name":{"type":["string","null"]},"description":{"type":["string","null"]},"unit":{"type":["string","null"]},"sum":{"oneOf":[{"$ref":"#/components/schemas/OTLPSum"},{"type":"null"}]},"gauge":{"oneOf":[{"$ref":"#/components/schemas/OTLPGauge"},{"type":"null"}]}}},"OTLPMetricsPayload":{"type":"object","description":"OTLP metrics payload in JSON format","properties":{"resourceMetrics":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceMetrics"}}}},"OTLPNumberDataPoint":{"type":"object","description":"Number data point","properties":{"attributes":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPKeyValue"}},"startTimeUnixNano":{"type":["string","null"]},"timeUnixNano":{"type":["string","null"]},"asInt":{"type":["integer","null"],"format":"int64"},"asDouble":{"type":["number","null"],"format":"double"}}},"OTLPResourceMetrics":{"type":"object","description":"Resource metrics containing scope metrics","properties":{"resource":{"oneOf":[{"$ref":"#/components/schemas/OTLPResource"},{"type":"null"}]},"scopeMetrics":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPScopeMetrics"}}}},"OTLPScopeMetrics":{"type":"object","description":"Scope metrics containing individual metrics","properties":{"scope":{"oneOf":[{"$ref":"#/components/schemas/OTLPScope"},{"type":"null"}]},"metrics":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPMetric"}}}},"OTLPSum":{"type":"object","description":"Sum metric","properties":{"dataPoints":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPNumberDataPoint"}},"aggregationTemporality":{"type":["integer","null"],"format":"int32"},"monotonic":{"type":"boolean"}}},"OTLPLogRecord":{"type":"object","description":"Individual log record","properties":{"timeUnixNano":{"type":["string","null"]},"observedTimeUnixNano":{"type":["string","null"]},"severityNumber":{"type":["integer","null"],"format":"int32"},"severityText":{"type":["string","null"]},"body":{"oneOf":[{"$ref":"#/components/schemas/OTLPAnyValue"},{"type":"null"}]},"attributes":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPKeyValue"}},"traceId":{"type":["string","null"]},"spanId":{"type":["string","null"]}}},"OTLPLogsPayload":{"type":"object","description":"OTLP logs payload in JSON format","properties":{"resourceLogs":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceLogs"}}}},"OTLPResourceLogs":{"type":"object","description":"Resource logs containing scope logs","properties":{"resource":{"oneOf":[{"$ref":"#/components/schemas/OTLPResource"},{"type":"null"}]},"scopeLogs":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPScopeLogs"}}}},"OTLPScopeLogs":{"type":"object","description":"Scope logs containing log records","properties":{"scope":{"oneOf":[{"$ref":"#/components/schemas/OTLPScope"},{"type":"null"}]},"logRecords":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPLogRecord"}}}},"OTLPUnifiedPayload":{"type":"object","description":"Unified OTLP payload containing logs and/or metrics","properties":{"resourceLogs":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceLogs"}},"resourceMetrics":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceMetrics"}},"resourceSpans":{"type":["array","null"],"items":{"$ref":"#/components/schemas/OTLPResourceSpans"}}}},"MeteringEvent":{"type":"object","description":"The metering event","properties":{"transactionId":{"type":"string","description":"The unique identifier of the metering event","example":"123e4567-e89b-12d3-a456-426614174000"},"payload":{"type":"object","additionalProperties":{},"description":"The rating payload as a JSON object containing key-value pairs representing usage metrics to track. For example, a SaaS application might send: { \"storageGB\": 15.5, \"apiCalls\": 1250, \"computeMinutes\": 480 }. If these keys do not already exist in Revenium, each key you send will be automatically configured as a metering element on the relevant data source.","example":{"storageGB":15.5,"apiCalls":1250,"computeMinutes":480}},"sourceId":{"type":["string","null"],"description":"Optional identifier for the source that represents the feature under which usage charges should be tracked. In the events endpoint, sources typically represent categories for billable units such as features, services, or resources (e.g., 'storageCharges' or 'CpuCharges'). If you wish for the key value pairs you send to be automatically applied to a source that is used in a product to calculate usage-based revenue, you should specify the relevant sourceId here. Sources must be pre-configured in the Revenium platform. The ID can be found on the sources page or retrieved via the list sources endpoint.","example":"5Agqrm:c4917580-281d-48e1-a206-05e595f006ec"},"subscriberCredential":{"type":["string","null"],"description":"Optional unique identifier for the subscriber/customer associated with this usage event. This credential maps the metered usage to a specific subscription and its associated product pricing rules. Can be any unique identifier from your system (customer ID, subscription ID, API key, etc.) that you've configured as a subscriber credential in the Revenium platform. Visible on the subscriber credentials page in Revenium.","example":"cust_abc123def456"},"sourceType":{"type":"string","default":"UNKNOWN","description":"Specifies the originating SDK or gateway of the metered event traffic. This is used for Revenium analytics only, and does not affect how Revenium processes and categorizes incoming metrics. Optional - defaults to 'UNKNOWN' if not specified.","enum":["UNKNOWN","AI","SDK_PYTHON","SDK_JS","SDK_JVM","SDK_SPRING","SDK_DOTNET","SDK_GOLANG","SDK_RUST","EBPF","AWS","AZURE","SNOWFLAKE","GRAVITEE","MULESOFT","BOOMI","REVENIUM","INTERNAL"],"example":"MULESOFT"}},"required":["payload","transactionId"]},"APIResponseMetadataResource":{"type":"object","description":"The metadata for the API response","properties":{"transactionId":{"type":"string","description":"A client-supplied unique identifier used to correlate request and response pairs across /meter/v2/apis/requests and /meter/v2/apis/response endpoints. Must be consistent between related API calls to ensure proper usage tracking and analytics.","example":"123e4567-e89b-12d3-a456-426614174000"},"totalDuration":{"type":["integer","null"],"format":"int64","description":"The total duration of the request processing in milliseconds","example":1500},"responseCode":{"type":"integer","format":"int32","description":"The HTTP status code of the response","example":200},"responseMessageSize":{"type":["integer","null"],"format":"int64","description":"The size of the response message in bytes","example":1024},"contentType":{"type":["string","null"],"description":"The content type of the request","example":"application/json"},"backendLatency":{"type":["number","null"],"format":"double","description":"The latency introduced by backend services in milliseconds","example":1200},"gatewayLatency":{"type":["number","null"],"format":"double","description":"The latency introduced by the gateway in milliseconds","example":50}},"required":["responseCode","transactionId"]},"APIRequestMetadataResource":{"type":"object","description":"The metadata for the API request","properties":{"transactionId":{"type":"string","description":"A client-supplied unique identifier used to correlate request and response pairs across /meter/v2/apis/requests and /meter/v2/apis/response endpoints. Must be consistent between related API calls to ensure proper usage tracking and analytics.","example":"123e4567-e89b-12d3-a456-426614174000"},"sourceId":{"type":["string","null"],"description":"Sources are typically individual API endpoints.  For existing sources, the ID can be found in the Revenium platform on the sources page or retrieved programmatically via the list sources endpoint. A sourceId is created automatically for new sources.","example":"5Agqrm:c4917580-281d-48e1-a206-05e595f006ec"},"credential":{"type":["string","null"],"description":"The credential used to access the API (e.g., API key, OAuth token, or key alias). This identifier maps the API transaction to a specific subscriber and their associated subscription/product for proper usage tracking and billing. Visible on the subscriber credentials page in the Revenium platform. Credentials can be API keys or key aliases depending on your system architecture.","example":"sk_live_abc123def456"},"sourceType":{"type":"string","default":"UNKNOWN","description":"Specifies the originating platform or gateway of the metered API traffic. This helps Revenium properly process and categorize incoming metrics according to their source system architecture. If not specified, defaults to 'UNKNOWN'.","enum":["UNKNOWN","AI","SDK_PYTHON","SDK_JS","SDK_JVM","SDK_SPRING","SDK_DOTNET","SDK_GOLANG","SDK_RUST","EBPF","AWS","AZURE","SNOWFLAKE","GRAVITEE","MULESOFT","BOOMI","REVENIUM","INTERNAL"],"example":"MULESOFT"},"method":{"type":["string","null"],"description":"The HTTP method of the request","enum":["GET","POST","PUT","DELETE","PATCH","OPTIONS","HEAD"],"example":"GET"},"resource":{"type":["string","null"],"description":"\n            Visible in the ‘resource’ field when viewing sources in the revenium application. \n            The resource field (often a full URL or relative URI) can be used to auto-match \n            transactions to existing sources based on the URL/URI accessed in the API call.\n        ","example":"https://api.example.com/resource"},"contentType":{"type":["string","null"],"description":"The content type of the request","example":"application/json"},"remoteHost":{"type":["string","null"],"description":"The IP address for the origin of the request.  Used by Revenium to report API usage by geography.","example":"192.168.1.1"},"userAgent":{"type":["string","null"],"description":"The user agent of the request","example":"Mozilla/5.0"},"requestMessageSize":{"type":["integer","null"],"format":"int64","description":"The size of the request message in bytes","example":1024}},"required":["transactionId"]},"AIVideoMetadataResource":{"type":"object","description":"The AI video operation metadata","properties":{"transactionId":{"type":["string","null"],"description":"Unique identifier for this specific AI video transaction. Used for deduplication, correlation with request/response pairs, and transaction lookup in Revenium analytics. If not provided, a UUID will be auto-generated. For best practices, generate a UUID in your application before making the AI call and use the same ID when submitting to Revenium. You can use either 'spanId' (recommended) or 'transactionId'.","example":"123e4567-e89b-12d3-a456-426614174000"},"traceId":{"type":["string","null"],"description":"Optional trace identifier to group multiple related AI video calls that belong to the same overall user request or workflow. For example, if a single user query triggers multiple AI calls (e.g., generation + upscale), use the same traceId for all calls to analyze them together in Revenium's analytics. Leave null for standalone operations.","example":"123e4567-e89b-12d3-a456-426614174000"},"model":{"type":"string","description":"The AI model identifier used for this video operation. Should match the exact model name from your AI provider (e.g., 'gen-3', 'gen-2', 'pika-1.0', 'sora'). This is used for cost calculation, performance analytics, and model comparison reporting in Revenium. Valid model names in Revenium for proper cost estimate can be verified using the sources/ai/models endpoint.","example":"gen-3"},"provider":{"type":"string","description":"The underlying AI provider/vendor whose model is actually processing the request. This identifies which company's AI model is being used, regardless of how you're accessing it (direct API, proxy, or gateway). \n\nCommon values: 'RunwayML' (for Gen-2/Gen-3), 'Pika', 'OpenAI' (for Sora), 'Luma AI', 'Stability AI'. \n\nCustom values are accepted but may affect analytics categorization. If using Revenium middleware, this is typically auto-populated from the AI provider's API response.","example":"RunwayML"},"requestTime":{"type":"string","description":"The timestamp when your application sent the request to the AI provider, in ISO 8601 format with UTC timezone (e.g., '2025-03-02T15:04:05Z'). This is used to calculate request duration and analyze usage patterns over time. Set this to the time immediately before calling the AI provider's API.","example":"2025-03-02T15:04:05Z"},"responseTime":{"type":"string","description":"The timestamp when the AI video operation finished, in ISO 8601 format with UTC timezone. For async/queued jobs, this is when the video was ready for download. For sync requests, this is when the complete response was received. Used to calculate total request duration.","example":"2025-03-02T15:04:06Z"},"requestDuration":{"type":"integer","format":"int64","description":"The total duration of the AI video request in milliseconds, from request start to completion. Calculated as (responseTime - requestTime). This includes network latency, AI processing time, and any mediation/gateway overhead. Used for performance analytics and SLA monitoring.","example":1247},"operationType":{"type":["string","null"],"description":"The type of operation performed","enum":["CHAT","GENERATE","EMBED","CLASSIFY","SUMMARIZE","TRANSLATE","OTHER","TOOL_CALL","RERANK","SEARCH","MODERATION","VISION","TRANSFORM","GUARDRAIL","AUDIO","VIDEO","IMAGE"],"example":"VIDEO"},"operationSubtype":{"type":["string","null"],"description":"Technical classification of the specific video operation. Valid values: 'generation', 'upscale', 'extend', 'edit'. Invalid values will be rejected with HTTP 400. Important for billing: upscale is typically much cheaper than generation - missing values are accepted with a warning.","example":"generation"},"totalCost":{"type":["number","null"],"format":"double","description":"The total cost in USD for this video operation. Typically leave null to let Revenium automatically calculate the total based on duration, credits, and current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":5},"costType":{"type":"string","description":"The type of cost being tracked. Currently always 'AI' for AI video costs. This field is used internally by Revenium to categorize different types of metered usage. You typically do not need to set this field as it defaults to 'AI'.","enum":["AI"],"example":"AI"},"organizationName":{"type":["string","null"],"description":"The name of the subscriber's organization from your system to allow Revenium to track usage & costs by company. i.e. AcmeCorp. If several subscriberIds have the same organizationName, Revenium's reporting will show usage for the entire organization broken down by subscriberId. This field is used for lookup and auto-creation of organizations in Revenium.","example":"AcmeCorp"},"subscriptionId":{"type":["string","null"],"description":"Unique identifier of the subscription from your own system that you wish to use to correlate usage between Revenium & your application.","example":"subscriptionId-456789"},"productName":{"type":["string","null"],"description":"The name of the product from your system that you wish to use to correlate usage between Revenium & your application. This field is used for lookup and auto-creation of products in Revenium.","example":"Free Trial"},"agent":{"type":["string","null"],"description":"The AI agent that is making the request","example":"marketing-agent"},"environment":{"type":["string","null"],"description":"Deployment environment where this AI video operation was executed. Used for filtering and analyzing usage patterns across different deployment stages. Common values: 'production', 'staging', 'development', 'test'. Leave null if not tracking by environment.","example":"production"},"region":{"type":["string","null"],"description":"Cloud region or geographic location where this AI video operation was processed. Used for analyzing latency patterns, compliance requirements, and regional cost differences. Examples: 'us-east-1', 'eu-west-1', 'ap-southeast-2'. Leave null if not tracking by region.","example":"us-east-1"},"parentTransactionId":{"type":["string","null"],"description":"Parent transaction ID for hierarchical tracing. When an AI video operation is part of a larger workflow or spawned by another AI call, this field references the parent's spanId/transactionId. Used to build transaction trees and understand call hierarchies in complex multi-step AI workflows. Leave null for root-level transactions. You can use either 'parentSpanId' (recommended) or 'parentTransactionId'.","example":"parent-txn-123e4567-e89b-12d3-a456-426614174000"},"transactionName":{"type":["string","null"],"description":"Human-readable name for this transaction. Provides context about what this AI video operation is doing in business terms. Examples: 'Generate Product Video', 'Create Marketing Clip', 'Upscale User Content'. Used in trace visualization for better readability. Falls back to taskType if not provided.","example":"Generate Product Video"},"retryNumber":{"type":["integer","null"],"format":"int32","description":"Retry attempt number for this AI video operation. 0 indicates the first attempt (no retry), 1 indicates first retry, 2 indicates second retry, etc. Used for analyzing failure rates and retry patterns. Each retry attempt should be a separate transaction with incrementing retryNumber and the same traceId. Leave null or set to 0 for first attempts.","example":0},"traceType":{"type":["string","null"],"description":"Categorical identifier for grouping similar workflows (e.g., 'marketing_video_generation', 'product_demos'). Enables trace-level analytics and anomaly detection within workflow cohorts. Must contain only alphanumeric characters, hyphens, and underscores. Max 128 characters. Defaults to 'uncategorized' if not provided or invalid. All transactions in the same trace must have the same traceType.","example":"video_generation"},"traceName":{"type":["string","null"],"description":"Human-readable label for individual trace instances (e.g., 'Marketing Video Q4 2025'). Enables finding specific workflow executions. Can contain any UTF-8 string. Max 256 characters. All transactions in the same trace must have the same traceName.","example":"Marketing Video Q4 2025"},"ticketId":{"type":["string","null"],"description":"External ticket or issue ID for cost attribution (e.g., 'JIRA-123', 'LINEAR-456'). Max 256 characters.","example":"JIRA-123","maxLength":256,"minLength":0},"squadId":{"type":["string","null"],"description":"Identifier for multi-agent framework team or squad (e.g., ARK, CrewAI). Used to group AI operations by agent team for analytics and cost tracking. Free-form string, max 256 characters.","example":"research-squad"},"squadName":{"type":["string","null"],"description":"Human-readable name for the squad type (e.g., 'Loan Processing', 'Document Analysis'). Used for display in the UI and analytics grouping. If squadId is provided without squadName, squadId will be used as the display name.","example":"Loan Processing"},"squadRole":{"type":["string","null"],"description":"The agent's role within this squad execution (e.g., 'Document Extractor', 'Credit Checker'). Used to identify the purpose of each agent's contribution to the squad workflow.","example":"Document Extractor"},"agenticJobId":{"type":["string","null"],"description":"Unique identifier for the agentic job instance. Used to correlate all AI operations within a single job execution. Should be unique per job run (e.g., UUID or meaningful ID like 'loan-123-processing').","example":"job-abc123","pattern":"^(?!types$|conversion-funnel$)[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$"},"agenticJobName":{"type":["string","null"],"description":"Human-readable name for the agentic job. Used for display in the UI and analytics grouping. If agenticJobId is provided without agenticJobName, the ID will be used as the display name.","example":"Process Loan Application"},"agenticJobType":{"type":["string","null"],"description":"Category or type of the agentic job. Normalized to lowercase on ingest to prevent data fragmentation. Used for grouping jobs by type in analytics and ROI calculations.","example":"loan-processing"},"agenticJobVersion":{"type":["string","null"],"description":"Version identifier for the job definition. Used to track job evolution and compare performance across versions.","example":"1.0.0"},"errorReason":{"type":["string","null"],"description":"Error message or reason if the AI video operation failed. Include this field when the AI provider returns an error (e.g., content policy violation, rate limit exceeded, job failed). Used for error rate analytics and debugging. Leave null for successful operations.","example":"Content policy violation"},"errorCode":{"type":["integer","null"],"format":"int32","description":"HTTP error code if the operation failed (e.g., 429, 503, 504). Used with billingSkipped to determine no-charge scenarios.","example":429},"subscriber":{"oneOf":[{"$ref":"#/components/schemas/SubscriberResource"},{"type":"null"}]},"middlewareSource":{"type":["string","null"],"description":"Identifier of the Revenium middleware package or SDK that captured and submitted this AI video metadata. This field is AUTOMATICALLY SET by Revenium's middleware packages (e.g., 'revenium-runway-python', 'revenium-pika-node'). You typically should NOT manually set this field. It is used for analytics to track which integration methods are being used and for debugging middleware-specific issues.","example":"revenium-runway-python-v1.0.0"},"modelSource":{"type":["string","null"],"description":"The routing or aggregation layer used to access the AI model. This identifies whether you're calling the AI provider directly or through an intermediary service. \n\nCommon values: 'DIRECT', 'LITELLM', 'OPENROUTER', 'PORTKEY', or provider names when calling directly. \n\nCustom values are accepted for specialized routing layers or gateways. This field is used for integration tracking and analytics.","example":"DIRECT"},"taskType":{"type":["string","null"],"description":"Optional category to group related AI tasks for cost and performance analysis. Use consistent values to compare metrics across different models or vendors performing the same type of work. Examples: 'video-generation', 'marketing-videos', 'product-demos', 'social-content'. This is freeform text - choose values that match your use cases.","example":"video-generation"},"durationSeconds":{"type":"number","format":"double","description":"Video duration in seconds. Required for all video operations.","example":10},"fps":{"type":["integer","null"],"format":"int32","description":"Frames per second.","example":24},"resolution":{"type":["string","null"],"description":"Video resolution (e.g., '1920x1080', '4K', 'HD').","example":"1920x1080"},"creditsConsumed":{"type":["number","null"],"format":"double","description":"Credits consumed (for credit-based pricing like RunwayML).","example":100},"videoJobId":{"type":["string","null"],"description":"Async video job identifier for batch/queued processing. Named videoJobId to distinguish from other async job types (e.g., batch completions, image generation).","example":"runway-job-xyz789"},"requestedDurationSeconds":{"type":["number","null"],"format":"double","description":"Requested video duration in seconds (what user asked for). Required for per-second billing (Google Veo). Used for analytics and partial billing scenarios.","example":10},"creditRate":{"type":["number","null"],"format":"double","description":"USD conversion rate for credit-based billing (e.g., RunwayML $0.01/credit).","example":0.01},"asyncOperation":{"type":["boolean","null"],"description":"Whether this is an async/long-running operation (e.g., Veo video generation).","example":true},"completionStatus":{"type":["string","null"],"description":"Completion status for async operations.","enum":["SUCCESS","PARTIAL_TIMEOUT","FAILED"],"example":"SUCCESS"},"sourceTransactionId":{"type":["string","null"],"description":"Links this operation to a source transaction (e.g., upscale links to original generation).","example":"txn_runway_gen_001"},"inputMessages":{"type":["string","null"],"description":"Input prompts/messages for this video generation. JSON-serialized array of messages in the same format as the LLM endpoint. Used for prompt analytics and cost attribution."},"outputResponse":{"type":["string","null"],"description":"Output response content or metadata (e.g., generated video URLs, dimensions). Used for analytics and audit trail."},"promptsTruncated":{"type":["boolean","null"],"description":"Indicates if prompts were truncated due to size limits.","example":false},"billingUnit":{"type":"string","description":"How this operation should be billed. For video: PER_SECOND (Google Veo) or CREDITS (RunwayML). Routes cost calculation in backend. Defaults to PER_SECOND if not specified.","enum":["PER_IMAGE","PER_MINUTE","PER_SECOND","PER_CHARACTER","PER_TOKEN","CREDITS"],"example":"PER_SECOND"},"billingSkipped":{"type":["boolean","null"],"description":"If true, backend returns $0 cost. Set for free tier, rate-limited requests, or other no-charge scenarios.","example":false},"skipReason":{"type":["string","null"],"description":"Reason why billing was skipped.","enum":["FREE_TIER","RATE_LIMITED","QUOTA_EXCEEDED","CONTENT_POLICY_VIOLATION","CAPACITY_UNAVAILABLE","SERVICE_UNAVAILABLE"],"example":"FREE_TIER"},"pricingTier":{"type":["string","null"],"description":"Pricing tier for batch discounts. BATCH = 50% discount, STANDARD = normal pricing.","enum":["STANDARD","BATCH"],"example":"STANDARD"},"requestedServiceTier":{"type":["string","null"],"description":"Service tier requested by user (e.g., 'priority', 'default', 'flex').","example":"default"},"actualServiceTier":{"type":["string","null"],"description":"Actual service tier used for billing. May differ from requested if downgraded.","example":"default"},"priorityTier":{"type":["string","null"],"description":"Google priority tier: 'best_effort' (-30%), 'on_demand' (base), 'committed' (-20%).","example":"on_demand"}},"required":["durationSeconds","model","provider","requestDuration","requestTime","responseTime"]},"CredentialResource":{"type":"object","properties":{"name":{"type":["string","null"],"description":"An alias for an API key used by one or more users.  Used to track cost & performance by individual API keys.","example":"OpenAI Key (Production)"},"value":{"type":["string","null"],"description":"The key value associated with the subscriber (most commonly an API key). Used to track cost  & performance by API key value (normally used when the only identifier for a user is an API key). ","example":"pk-1234567"}}},"SubscriberResource":{"type":"object","description":"Subscriber metadata","properties":{"id":{"type":["string","null"],"description":"Track cost & performance by individual users (if customers are anonymous or tracking by emails is not desired).  If several subscriberIds are submitted with the same organizationName, Revenium's reporting will show usage for the entire organization broken down by subscriberId.","example":"subscriberId-123456"},"email":{"type":["string","null"],"description":"The email address of the subscriber.  Used to track cost & performance by individual users if customer e-mail addresses are known.","example":"user@example.com"},"credential":{"oneOf":[{"$ref":"#/components/schemas/CredentialResource"},{"type":"null"}]}}},"AIImageMetadataResource":{"type":"object","description":"The AI image operation metadata","properties":{"transactionId":{"type":["string","null"],"description":"Unique identifier for this specific AI image transaction. Used for deduplication, correlation with request/response pairs, and transaction lookup in Revenium analytics. If not provided, a UUID will be auto-generated. For best practices, generate a UUID in your application before making the AI call and use the same ID when submitting to Revenium. You can use either 'spanId' (recommended) or 'transactionId'.","example":"123e4567-e89b-12d3-a456-426614174000"},"traceId":{"type":["string","null"],"description":"Optional trace identifier to group multiple related AI image calls that belong to the same overall user request or workflow. For example, if a single user query triggers multiple AI calls (e.g., generation + variation), use the same traceId for all calls to analyze them together in Revenium's analytics. Leave null for standalone operations.","example":"123e4567-e89b-12d3-a456-426614174000"},"model":{"type":"string","description":"The AI model identifier used for this image operation. Should match the exact model name from your AI provider (e.g., 'dall-e-3', 'dall-e-2', 'stable-diffusion-xl'). This is used for cost calculation, performance analytics, and model comparison reporting in Revenium. Valid model names in Revenium for proper cost estimate can be verified using the sources/ai/models endpoint.","example":"dall-e-3"},"provider":{"type":"string","description":"The underlying AI provider/vendor whose model is actually processing the request. This identifies which company's AI model is being used, regardless of how you're accessing it (direct API, proxy, or gateway). \n\nCommon values: 'OpenAI' (for DALL-E), 'Stability AI' (for Stable Diffusion), 'Midjourney', 'Adobe'. \n\nCustom values are accepted but may affect analytics categorization. If using Revenium middleware, this is typically auto-populated from the AI provider's API response.","example":"OpenAI"},"requestTime":{"type":"string","description":"The timestamp when your application sent the request to the AI provider, in ISO 8601 format with UTC timezone (e.g., '2025-03-02T15:04:05Z'). This is used to calculate request duration and analyze usage patterns over time. Set this to the time immediately before calling the AI provider's API.","example":"2025-03-02T15:04:05Z"},"responseTime":{"type":"string","description":"The timestamp when the AI image operation finished, in ISO 8601 format with UTC timezone. This is when the complete response (image URLs or base64 data) was received. Used to calculate total request duration.","example":"2025-03-02T15:04:06Z"},"requestDuration":{"type":"integer","format":"int64","description":"The total duration of the AI image request in milliseconds, from request start to completion. Calculated as (responseTime - requestTime). This includes network latency, AI processing time, and any mediation/gateway overhead. Used for performance analytics and SLA monitoring.","example":1247},"operationType":{"type":["string","null"],"description":"The type of operation performed","enum":["CHAT","GENERATE","EMBED","CLASSIFY","SUMMARIZE","TRANSLATE","OTHER","TOOL_CALL","RERANK","SEARCH","MODERATION","VISION","TRANSFORM","GUARDRAIL","AUDIO","VIDEO","IMAGE"],"example":"IMAGE"},"operationSubtype":{"type":["string","null"],"description":"Technical classification of the specific image operation. Valid values: 'generation', 'edit', 'variation', 'upscale', 'inpainting'. Invalid values will be rejected with HTTP 400. Recommended for billing routing - missing values are accepted with a warning.","example":"generation"},"totalCost":{"type":["number","null"],"format":"double","description":"The total cost in USD for this image operation. Typically leave null to let Revenium automatically calculate the total based on image count, resolution, and current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":0.04},"costType":{"type":"string","description":"The type of cost being tracked. Currently always 'AI' for AI image costs. This field is used internally by Revenium to categorize different types of metered usage. You typically do not need to set this field as it defaults to 'AI'.","enum":["AI"],"example":"AI"},"organizationName":{"type":["string","null"],"description":"The name of the subscriber's organization from your system to allow Revenium to track usage & costs by company. i.e. AcmeCorp. If several subscriberIds have the same organizationName, Revenium's reporting will show usage for the entire organization broken down by subscriberId. This field is used for lookup and auto-creation of organizations in Revenium.","example":"AcmeCorp"},"subscriptionId":{"type":["string","null"],"description":"Unique identifier of the subscription from your own system that you wish to use to correlate usage between Revenium & your application.","example":"subscriptionId-456789"},"productName":{"type":["string","null"],"description":"The name of the product from your system that you wish to use to correlate usage between Revenium & your application. This field is used for lookup and auto-creation of products in Revenium.","example":"Free Trial"},"agent":{"type":["string","null"],"description":"The AI agent that is making the request","example":"marketing-agent"},"environment":{"type":["string","null"],"description":"Deployment environment where this AI image operation was executed. Used for filtering and analyzing usage patterns across different deployment stages. Common values: 'production', 'staging', 'development', 'test'. Leave null if not tracking by environment.","example":"production"},"region":{"type":["string","null"],"description":"Cloud region or geographic location where this AI image operation was processed. Used for analyzing latency patterns, compliance requirements, and regional cost differences. Examples: 'us-east-1', 'eu-west-1', 'ap-southeast-2'. Leave null if not tracking by region.","example":"us-east-1"},"parentTransactionId":{"type":["string","null"],"description":"Parent transaction ID for hierarchical tracing. When an AI image operation is part of a larger workflow or spawned by another AI call, this field references the parent's spanId/transactionId. Used to build transaction trees and understand call hierarchies in complex multi-step AI workflows. Leave null for root-level transactions. You can use either 'parentSpanId' (recommended) or 'parentTransactionId'.","example":"parent-txn-123e4567-e89b-12d3-a456-426614174000"},"transactionName":{"type":["string","null"],"description":"Human-readable name for this transaction. Provides context about what this AI image operation is doing in business terms. Examples: 'Generate Product Image', 'Create Marketing Banner', 'Edit Background'. Used in trace visualization for better readability. Falls back to taskType if not provided.","example":"Generate Product Image"},"retryNumber":{"type":["integer","null"],"format":"int32","description":"Retry attempt number for this AI image operation. 0 indicates the first attempt (no retry), 1 indicates first retry, 2 indicates second retry, etc. Used for analyzing failure rates and retry patterns. Each retry attempt should be a separate transaction with incrementing retryNumber and the same traceId. Leave null or set to 0 for first attempts.","example":0},"traceType":{"type":["string","null"],"description":"Categorical identifier for grouping similar workflows (e.g., 'product_image_generation', 'marketing_assets'). Enables trace-level analytics and anomaly detection within workflow cohorts. Must contain only alphanumeric characters, hyphens, and underscores. Max 128 characters. Defaults to 'uncategorized' if not provided or invalid. All transactions in the same trace must have the same traceType.","example":"image_generation"},"traceName":{"type":["string","null"],"description":"Human-readable label for individual trace instances (e.g., 'Marketing Campaign Q4'). Enables finding specific workflow executions. Can contain any UTF-8 string. Max 256 characters. All transactions in the same trace must have the same traceName.","example":"Marketing Campaign Q4"},"ticketId":{"type":["string","null"],"description":"External ticket or issue ID for cost attribution (e.g., 'JIRA-123', 'LINEAR-456'). Max 256 characters.","example":"JIRA-123","maxLength":256,"minLength":0},"squadId":{"type":["string","null"],"description":"Identifier for multi-agent framework team or squad (e.g., ARK, CrewAI). Used to group AI operations by agent team for analytics and cost tracking. Free-form string, max 256 characters.","example":"research-squad"},"squadName":{"type":["string","null"],"description":"Human-readable name for the squad type (e.g., 'Loan Processing', 'Document Analysis'). Used for display in the UI and analytics grouping. If squadId is provided without squadName, squadId will be used as the display name.","example":"Loan Processing"},"squadRole":{"type":["string","null"],"description":"The agent's role within this squad execution (e.g., 'Document Extractor', 'Credit Checker'). Used to identify the purpose of each agent's contribution to the squad workflow.","example":"Document Extractor"},"agenticJobId":{"type":["string","null"],"description":"Unique identifier for the agentic job instance. Used to correlate all AI operations within a single job execution. Should be unique per job run (e.g., UUID or meaningful ID like 'loan-123-processing').","example":"job-abc123","pattern":"^(?!types$|conversion-funnel$)[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$"},"agenticJobName":{"type":["string","null"],"description":"Human-readable name for the agentic job. Used for display in the UI and analytics grouping. If agenticJobId is provided without agenticJobName, the ID will be used as the display name.","example":"Process Loan Application"},"agenticJobType":{"type":["string","null"],"description":"Category or type of the agentic job. Normalized to lowercase on ingest to prevent data fragmentation. Used for grouping jobs by type in analytics and ROI calculations.","example":"loan-processing"},"agenticJobVersion":{"type":["string","null"],"description":"Version identifier for the job definition. Used to track job evolution and compare performance across versions.","example":"1.0.0"},"errorReason":{"type":["string","null"],"description":"Error message or reason if the AI image operation failed. Include this field when the AI provider returns an error (e.g., content policy violation, rate limit exceeded, invalid parameters). Used for error rate analytics and debugging. Leave null for successful operations.","example":"Content policy violation"},"errorCode":{"type":["integer","null"],"format":"int32","description":"HTTP error code if the operation failed (e.g., 429, 503, 500). Used with billingSkipped to determine no-charge scenarios (e.g., OpenAI flex tier 429 = no charge).","example":429},"subscriber":{"oneOf":[{"$ref":"#/components/schemas/SubscriberResource"},{"type":"null"}]},"middlewareSource":{"type":["string","null"],"description":"Identifier of the Revenium middleware package or SDK that captured and submitted this AI image metadata. This field is AUTOMATICALLY SET by Revenium's middleware packages (e.g., 'revenium-openai-python', 'revenium-stability-node'). You typically should NOT manually set this field. It is used for analytics to track which integration methods are being used and for debugging middleware-specific issues.","example":"revenium-openai-python-v1.2.3"},"modelSource":{"type":["string","null"],"description":"The routing or aggregation layer used to access the AI model. This identifies whether you're calling the AI provider directly or through an intermediary service. \n\nCommon values: 'DIRECT', 'LITELLM', 'OPENROUTER', 'PORTKEY', or provider names when calling directly. \n\nCustom values are accepted for specialized routing layers or gateways. This field is used for integration tracking and analytics.","example":"DIRECT"},"taskType":{"type":["string","null"],"description":"Optional category to group related AI tasks for cost and performance analysis. Use consistent values to compare metrics across different models or vendors performing the same type of work. Examples: 'image-generation', 'product-photos', 'marketing-assets', 'avatar-creation'. This is freeform text - choose values that match your use cases.","example":"image-generation"},"requestedImageCount":{"type":["integer","null"],"format":"int32","description":"Number of images requested in the API call.","example":4},"actualImageCount":{"type":"integer","format":"int32","description":"Number of images actually generated/returned. Required for all image operations.","example":4},"resolution":{"type":["string","null"],"description":"Image resolution (e.g., '1024x1024', '1792x1024', '512x512').","example":"1024x1024"},"quality":{"type":["string","null"],"description":"Image quality setting (e.g., 'standard', 'hd'). HD typically costs 2x standard.","example":"hd"},"style":{"type":["string","null"],"description":"Image style for DALL-E 3 (e.g., 'vivid', 'natural'). Does not affect pricing.","example":"vivid"},"format":{"type":["string","null"],"description":"Output format for the generated image (e.g., 'url', 'b64_json'). Does not affect pricing. Used for analytics only.","example":"url"},"sourceImageProvided":{"type":["boolean","null"],"description":"Whether a source image was provided for this operation. True for edit/variation/inpaint operations, false for pure generation. Used to distinguish generation from modification operations in analytics.","example":false},"sourceTransactionId":{"type":["string","null"],"description":"Links this operation to a source transaction (e.g., variation links to original generation). Used for lineage tracking in analytics.","example":"txn_dalle_gen_001"},"revisedPromptProvided":{"type":["boolean","null"],"description":"Whether DALL-E 3 revised the original prompt. DALL-E 3 automatically rewrites prompts for safety and quality. Used for analytics only.","example":true},"inputMessages":{"type":["string","null"],"description":"Input prompts/messages for this image generation. JSON-serialized array of messages in the same format as the LLM endpoint. Used for prompt analytics and cost attribution."},"outputResponse":{"type":["string","null"],"description":"Output response content or metadata (e.g., generated image URLs, dimensions). Used for analytics and audit trail."},"promptsTruncated":{"type":["boolean","null"],"description":"Indicates if prompts were truncated due to size limits.","example":false},"billingUnit":{"type":"string","description":"How this operation should be billed. For images this is always PER_IMAGE. Routes cost calculation in backend.","enum":["PER_IMAGE","PER_MINUTE","PER_SECOND","PER_CHARACTER","PER_TOKEN","CREDITS"],"example":"PER_IMAGE"},"billingSkipped":{"type":["boolean","null"],"description":"If true, backend returns $0 cost. Set for free tier, rate-limited requests (429 on flex), or other no-charge scenarios.","example":false},"skipReason":{"type":["string","null"],"description":"Reason why billing was skipped.","enum":["FREE_TIER","RATE_LIMITED","QUOTA_EXCEEDED","CONTENT_POLICY_VIOLATION","CAPACITY_UNAVAILABLE","SERVICE_UNAVAILABLE"],"example":"FREE_TIER"},"pricingTier":{"type":["string","null"],"description":"Pricing tier for batch discounts. BATCH = 50% discount, STANDARD = normal pricing.","enum":["STANDARD","BATCH"],"example":"STANDARD"},"requestedServiceTier":{"type":["string","null"],"description":"Service tier requested by user (e.g., 'priority', 'default', 'flex').","example":"default"},"actualServiceTier":{"type":["string","null"],"description":"Actual service tier used for billing. May differ from requested if downgraded. Backend uses this for cost calculation.","example":"default"},"priorityTier":{"type":["string","null"],"description":"Google priority tier for Vertex AI pricing. 'best_effort' = -30%, 'on_demand' = base rate, 'committed' = -20%. Only applies to Google providers.","example":"on_demand"}},"required":["actualImageCount","model","provider","requestDuration","requestTime","responseTime"]},"AICompletionMetadataResource":{"type":"object","description":"The AI completion metadata","properties":{"transactionId":{"type":["string","null"],"description":"Unique identifier for this specific AI completion transaction. Used for deduplication, correlation with request/response pairs, and transaction lookup in Revenium analytics. If not provided, a UUID will be auto-generated. For best practices, generate a UUID in your application before making the AI call and use the same ID when submitting to Revenium. You can use either 'spanId' (recommended) or 'transactionId'.","example":"123e4567-e89b-12d3-a456-426614174000"},"traceId":{"type":["string","null"],"description":"Optional trace identifier to group multiple related AI completion calls that belong to the same overall user request or workflow. For example, if a single user query triggers multiple LLM calls (e.g., retrieval + generation), use the same traceId for all calls to analyze them together in Revenium's analytics. Leave null for standalone completions.","example":"123e4567-e89b-12d3-a456-426614174000"},"model":{"type":"string","description":"The AI model identifier used for this completion. Should match the exact model name from your AI provider (e.g., 'gpt-4', 'claude-3-opus-20240229', 'gemini-pro'). This is used for cost calculation, performance analytics, and model comparison reporting in Revenium. Valid model names in Revenium for proper cost estimate can be verified using the sources/ai/models endpoint.","example":"gpt-4"},"responseQualityScore":{"type":["number","null"],"format":"double","description":"Optional quality score for the AI response on a 0.0-1.0 scale. Set by your application's evaluation logic (e.g., RAGAS, human feedback, custom scoring). Used in Revenium analytics to correlate quality with cost, model choice, and other metrics. Leave null if not tracking quality scores.","example":0.9},"modelSource":{"type":["string","null"],"description":"The routing or aggregation layer used to access the AI model. This identifies whether you're calling the AI provider directly or through an intermediary service. \n\nCommon values: 'DIRECT', 'LITELLM', 'OPENROUTER', 'PORTKEY', 'AZURE_OPENAI', or provider names ('OPENAI', 'ANTHROPIC', 'GOOGLE', etc.) when calling directly. \n\nCustom values are accepted for specialized routing layers or gateways. This field is used for integration tracking and analytics.","example":"LITELLM"},"inputTokenCount":{"type":"integer","format":"int64","description":"The count of consumed input tokens","example":50},"outputTokenCount":{"type":"integer","format":"int64","description":"The count of consumed output tokens","example":150},"reasoningTokenCount":{"type":["integer","null"],"format":"int64","description":"The number of reasoning tokens used in the completion. Reasoning tokens are extended thinking tokens used by AI models for complex problem-solving. These are sometimes billed separately from regular input/output tokens. Only include this field if your AI provider reports reasoning tokens Revenium's middleware will always populate this field if reasoning tokens are reported by the AI provider. Leave null for models without reasoning capabilities.","example":1300},"cacheCreationTokenCount":{"type":["integer","null"],"format":"int64","description":"The number of tokens used to create new cache entries (prompt caching). When you send a long prompt for the first time, the AI provider may cache it for faster subsequent requests. Cache creation tokens are typically billed at a higher rate than regular input tokens. Only include if your provider supports prompt caching (e.g., Anthropic Claude, OpenAI with cache-enabled models). Revenium's middleware will always populate this field automatically. Leave null otherwise.","example":1300},"cacheReadTokenCount":{"type":["integer","null"],"format":"int64","description":"The number of tokens read from cache (prompt caching). When reusing a previously cached prompt, these tokens are read from cache instead of being processed as new input tokens. Cache read tokens are typically billed at a lower rate than regular input tokens. Only include if your provider supports prompt caching and reports cache hits. Revenium's middleware will always populate this field automatically. Leave null otherwise.","example":1300},"totalTokenCount":{"type":"integer","format":"int64","description":"The total number of tokens","example":200},"stopReason":{"type":"string","description":"The reason for stopping the completion. Canonical values are accepted case-insensitively. Common provider aliases are also accepted, including OpenAI finish reasons ('stop', 'length', 'tool_calls', 'function_call', 'content_filter') and Anthropic stop reasons ('end_turn', 'max_tokens', 'tool_use', 'stop_sequence'). Responses and exports use the canonical uppercase values.","enum":["END","END_SEQUENCE","TIMEOUT","TOKEN_LIMIT","COST_LIMIT","COMPLETION_LIMIT","ERROR","CANCELLED","CONTENT_FILTER","TOOL_CALL"],"example":"END"},"inputTokenCost":{"type":["number","null"],"format":"double","description":"The cost in USD for input tokens in this completion. Typically leave null to let Revenium automatically calculate costs based on the model and provider's current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. Note: Manual cost override may not be available on all Revenium plans.","example":0.0015},"outputTokenCost":{"type":["number","null"],"format":"double","description":"The cost in USD for output tokens in this completion. Typically leave null to let Revenium automatically calculate costs based on the model and provider's current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation. Note: Manual cost override may not be available on all Revenium plans.","example":0.006},"cacheCreationTokenCost":{"type":["number","null"],"format":"double","description":"The cost in USD for cache creation tokens in this completion. Typically leave null to let Revenium automatically calculate costs based on the model and provider's caching pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":0.0037},"cacheReadTokenCost":{"type":["number","null"],"format":"double","description":"The cost in USD for cache read tokens in this completion. Typically leave null to let Revenium automatically calculate costs based on the model and provider's caching pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":0.0001},"totalCost":{"type":["number","null"],"format":"double","description":"The total cost in USD for this completion (sum of all token costs). Typically leave null to let Revenium automatically calculate the total based on token counts and current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":0.0213},"costType":{"type":"string","description":"The type of cost being tracked. Currently always 'AI' for AI completion costs. This field is used internally by Revenium to categorize different types of metered usage. You typically do not need to set this field as it defaults to 'AI'.","enum":["AI"],"example":"AI"},"requestTime":{"type":"string","description":"The timestamp when your application sent the request to the AI provider, in ISO 8601 format with UTC timezone (e.g., '2025-03-02T15:04:05Z'). This is used to calculate request duration and analyze usage patterns over time. Set this to the time immediately before calling the AI provider's API.","example":"2025-03-02T15:04:05Z"},"completionStartTime":{"type":"string","description":"The timestamp when the AI completion started generating output, in ISO 8601 format with UTC timezone. For streaming requests, this is when the first token was received. For non-streaming requests, this is typically the same as or very close to responseTime. Used to calculate time-to-first-token latency for streaming completions.","example":"2025-03-02T15:04:05Z"},"timeToFirstToken":{"type":["integer","null"],"format":"int64","description":"The latency in milliseconds from request start to first token received. Calculated as (completionStartTime - requestTime). This metric is particularly important for streaming completions to measure perceived responsiveness. For non-streaming completions, this may be null or equal to requestDuration.","example":245},"responseTime":{"type":"string","description":"The timestamp when the AI completion finished, in ISO 8601 format with UTC timezone. For streaming requests, this is when the last token was received and the stream closed. For non-streaming requests, this is when the complete response was received. Used to calculate total request duration.","example":"2025-03-02T15:04:06Z"},"requestDuration":{"type":"integer","format":"int64","description":"The total duration of the AI completion request in milliseconds, from request start to completion. Calculated as (responseTime - requestTime). This includes network latency, AI processing time, and any mediation/gateway overhead. Used for performance analytics and SLA monitoring.","example":1247},"mediationLatency":{"type":["integer","null"],"format":"int64","description":"The latency in milliseconds introduced by intermediate systems between your application and the AI provider, such as API gateways, proxies, or AI mediation layers. This helps identify performance bottlenecks outside of the AI provider's processing time. Leave null if not using intermediate systems or if latency is not tracked separately.","example":45},"provider":{"type":"string","description":"The underlying AI provider/vendor whose model is actually processing the request. This identifies which company's AI model is being used, regardless of how you're accessing it (direct API, proxy, or gateway). \n\nCommon values: 'OpenAI' (for GPT models), 'Anthropic' (for Claude models), 'Google' (for Gemini models), 'Cohere', 'Mistral', 'Meta' (for Llama models), 'Amazon Bedrock', 'Azure'. \n\nCustom values are accepted but may affect analytics categorization. Revenium looks up model pricing primarily by model name (e.g., 'gpt-4', 'claude-3-opus'), so using non-standard provider names will not break cost calculation. However, using standard provider names ensures proper categorization in analytics and reporting. \n\nIf using an aggregation service like LiteLLM or OpenRouter, this should still be the actual provider (e.g., 'Anthropic' not 'LiteLLM'). If using Revenium middleware, this is typically auto-populated from the AI provider's API response. Supported provider models can be verified using the sources/ai/models endpoint which returns both providers and model names.","example":"Anthropic"},"taskType":{"type":["string","null"],"description":"Optional category to group related AI tasks for cost and performance analysis. Use consistent values to compare metrics across different models or vendors performing the same type of work. Examples: 'chat', 'summarization', 'code-generation', 'translation', 'image-generation', 'embeddings', 'classification', 'sentiment-analysis'. This is freeform text - choose values that match your use cases.","example":"code-generation"},"organizationName":{"type":["string","null"],"description":"The name of the subscriber's organization from your system to allow Revenium to track usage & costs by company. i.e. AcmeCorp. If several subscriberIds have the same organizationName, Revenium's reporting will show usage for the entire organization broken down by subscriberId. This field is used for lookup and auto-creation of organizations in Revenium.","example":"AcmeCorp"},"subscriptionId":{"type":["string","null"],"description":"Unique identifier of the subscription from your own system that you wish to use to correlate usage between Revenium & your application.","example":"subscriptionId-456789"},"productName":{"type":["string","null"],"description":"The name of the product from your system that you wish to use to correlate usage between Revenium & your application. This field is used for lookup and auto-creation of products in Revenium.","example":"Free Trial"},"agent":{"type":["string","null"],"description":"The AI agent that is making the request","example":"marketing-agent"},"operationType":{"type":["string","null"],"description":"The type of operation performed","enum":["CHAT","GENERATE","EMBED","CLASSIFY","SUMMARIZE","TRANSLATE","OTHER","TOOL_CALL","RERANK","SEARCH","MODERATION","VISION","TRANSFORM","GUARDRAIL","AUDIO","VIDEO","IMAGE"],"example":"CHAT"},"systemFingerprint":{"type":["string","null"],"description":"A unique identifier provided by the AI provider that represents the statistical signature of the language model that generated this completion. This fingerprint can be used for model attribution, debugging, and monitoring model behavior across requests. Automatically provided by some AI providers (e.g., OpenAI) in their API responses. Leave null if your provider does not supply this value.","example":"fp_44z789a1c23def456gh7890ijkl1234mnopq567rstuv8910wxyz"},"temperature":{"type":["number","null"],"format":"double","description":"The temperature parameter used for this completion, controlling randomness in the AI's output. Typically ranges from 0.0 (deterministic) to 2.0 (very random). Track this to correlate temperature settings with response quality, cost, or other metrics. Useful for A/B testing different temperature values.","example":0.7},"errorReason":{"type":["string","null"],"description":"Error message or reason if the AI completion failed. Include this field when the AI provider returns an error (e.g., rate limit exceeded, invalid API key, model not found, content policy violation). Used for error rate analytics and debugging. Leave null for successful completions.","example":"Rate limit exceeded for model gpt-4"},"errorCode":{"type":["integer","null"],"format":"int32","description":"HTTP error code if the completion failed (e.g., 429, 503, 500). Used with billingSkipped to determine no-charge scenarios (e.g., OpenAI flex tier 429 = no charge).","example":429},"subscriber":{"oneOf":[{"$ref":"#/components/schemas/SubscriberResource"},{"type":"null"}]},"middlewareSource":{"type":["string","null"],"description":"Identifier of the Revenium middleware package or SDK that captured and submitted this AI completion metadata. This field is AUTOMATICALLY SET by Revenium's middleware packages (e.g., 'revenium-openai-python', 'revenium-anthropic-node'). You typically should NOT manually set this field. It is used for analytics to track which integration methods are being used and for debugging middleware-specific issues.","example":"revenium-openai-python-v1.2.3"},"environment":{"type":["string","null"],"description":"Deployment environment where this AI completion was executed. Used for filtering and analyzing usage patterns across different deployment stages. Common values: 'production', 'staging', 'development', 'test'. Leave null if not tracking by environment.","example":"production"},"operationSubtype":{"type":["string","null"],"description":"Technical classification of the specific operation or tool used within the AI completion. This provides finer-grained categorization than operationType. Examples: 'web_search', 'function_call', 'code_interpreter', 'sql_query', 'http_request', 'file_read', 'ocr'. Used for analyzing which tools or capabilities are being used most frequently. Leave null for standard completions without tool usage.","example":"web_search"},"parentTransactionId":{"type":["string","null"],"description":"Parent transaction ID for hierarchical tracing. When an AI completion is part of a larger workflow or spawned by another AI call, this field references the parent's spanId/transactionId. Used to build transaction trees and understand call hierarchies in complex multi-step AI workflows. Leave null for root-level transactions. You can use either 'parentSpanId' (recommended) or 'parentTransactionId'.","example":"parent-txn-123e4567-e89b-12d3-a456-426614174000"},"transactionName":{"type":["string","null"],"description":"Human-readable name for this transaction. Provides context about what this AI completion is doing in business terms. Examples: 'Summarize Application', 'Credit Risk Analysis', 'Customer Support Response'. Used in trace visualization for better readability. Falls back to taskType if not provided.","example":"Summarize Application"},"region":{"type":["string","null"],"description":"Cloud region or geographic location where this AI completion was processed. Used for analyzing latency patterns, compliance requirements, and regional cost differences. Examples: 'us-east-1', 'eu-west-1', 'ap-southeast-2'. Leave null if not tracking by region.","example":"us-east-1"},"retryNumber":{"type":["integer","null"],"format":"int32","description":"Retry attempt number for this AI completion. 0 indicates the first attempt (no retry), 1 indicates first retry, 2 indicates second retry, etc. Used for analyzing failure rates and retry patterns. Each retry attempt should be a separate transaction with incrementing retryNumber and the same traceId. Leave null or set to 0 for first attempts.","example":0},"traceType":{"type":["string","null"],"description":"Categorical identifier for grouping similar workflows (e.g., 'create_video', 'write_script'). Enables trace-level analytics and anomaly detection within workflow cohorts. Must contain only alphanumeric characters, hyphens, and underscores. Max 128 characters. Defaults to 'uncategorized' if not provided or invalid. All transactions in the same trace must have the same traceType.","example":"document_analysis"},"traceName":{"type":["string","null"],"description":"Human-readable label for individual trace instances (e.g., 'Marketing Video Q4 2025'). Enables finding specific workflow executions. Can contain any UTF-8 string. Max 256 characters. All transactions in the same trace must have the same traceName.","example":"Customer Onboarding - Acme Corp"},"ticketId":{"type":["string","null"],"description":"External ticket or issue ID for cost attribution (e.g., 'JIRA-123', 'LINEAR-456'). Max 256 characters.","example":"JIRA-123","maxLength":256,"minLength":0},"squadId":{"type":["string","null"],"description":"Identifier for multi-agent framework team or squad (e.g., ARK, CrewAI). Used to group AI operations by agent team for analytics and cost tracking. Free-form string, max 256 characters.","example":"research-squad"},"squadName":{"type":["string","null"],"description":"Human-readable name for the squad type (e.g., 'Loan Processing', 'Document Analysis'). Used for display in the UI and analytics grouping. If squadId is provided without squadName, squadId will be used as the display name.","example":"Loan Processing"},"squadRole":{"type":["string","null"],"description":"The agent's role within this squad execution (e.g., 'Document Extractor', 'Credit Checker'). Used to identify the purpose of each agent's contribution to the squad workflow.","example":"Document Extractor"},"skillName":{"type":["string","null"]},"skillInvocationTrigger":{"type":["string","null"]},"skillSource":{"type":["string","null"]},"skillKind":{"type":["string","null"]},"skillPluginName":{"type":["string","null"]},"skillMarketplaceName":{"type":["string","null"]},"agenticJobId":{"type":["string","null"],"description":"Unique identifier for the agentic job instance. Used to correlate all AI operations within a single job execution. Should be unique per job run (e.g., UUID or meaningful ID like 'loan-123-processing').","example":"job-abc123","pattern":"^(?!types$|conversion-funnel$)[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$"},"agenticJobName":{"type":["string","null"],"description":"Human-readable name for the agentic job. Used for display in the UI and analytics grouping. If agenticJobId is provided without agenticJobName, the ID will be used as the display name.","example":"Process Loan Application"},"agenticJobType":{"type":["string","null"],"description":"Category or type of the agentic job. Normalized to lowercase on ingest to prevent data fragmentation. Used for grouping jobs by type in analytics and ROI calculations.","example":"loan-processing"},"agenticJobVersion":{"type":["string","null"],"description":"Version identifier for the job definition. Used to track job evolution and compare performance across versions.","example":"1.0.0"},"systemPrompt":{"type":["string","null"],"description":"System prompt/instructions sent to the model."},"inputMessages":{"type":["string","null"],"description":"User input messages as JSON array."},"outputResponse":{"type":["string","null"],"description":"Assistant output/response content."},"promptsTruncated":{"type":["boolean","null"],"description":"Indicates if prompts were truncated due to size limits.","example":false},"billingSkipped":{"type":["boolean","null"],"description":"If true, backend returns $0 cost. Set for free tier, rate-limited requests (429 on flex), or other no-charge scenarios.","example":false},"skipReason":{"type":["string","null"],"description":"Reason why billing was skipped.","enum":["FREE_TIER","RATE_LIMITED","QUOTA_EXCEEDED","CONTENT_POLICY_VIOLATION","CAPACITY_UNAVAILABLE","SERVICE_UNAVAILABLE"],"example":"RATE_LIMITED"},"pricingTier":{"type":["string","null"],"description":"Pricing tier for batch discounts. BATCH = 50% discount, STANDARD = normal pricing.","enum":["STANDARD","BATCH"],"example":"STANDARD"},"requestedServiceTier":{"type":["string","null"],"description":"Service tier requested by user (e.g., 'priority', 'default', 'flex').","example":"default"},"actualServiceTier":{"type":["string","null"],"description":"Actual service tier used for billing. May differ from requested if downgraded. Backend uses this for cost calculation.","example":"default"},"subscriptionTier":{"type":["string","null"],"description":"The subscription tier for coding assistant tools (e.g., 'pro', 'free', 'unknown'). Only populated for coding_assistant cost sources.","example":"pro"},"costMultiplier":{"type":["number","null"],"format":"double","description":"Multiplier applied to raw AI provider costs for this coding assistant event. Used to normalize costs relative to subscription pricing.","example":1},"codingAssistantAccountUuid":{"type":["string","null"],"description":"Account UUID from the coding assistant tool (e.g., CLAUDE_CODE_ACCOUNT_UUID). Used for subscriber upsert to correlate coding assistant usage to a specific account.","example":"123e4567-e89b-12d3-a456-426614174000"},"cacheCreation5mTokenCount":{"type":["integer","null"],"format":"int64","description":"The portion of cacheCreationTokenCount written with a 5-minute cache TTL (Anthropic ephemeral_5m_input_tokens). When supplied, the 5m and 1h buckets sum to cacheCreationTokenCount. Leave null if the provider does not report a TTL split.","example":1000},"cacheCreation1hTokenCount":{"type":["integer","null"],"format":"int64","description":"The portion of cacheCreationTokenCount written with a 1-hour cache TTL (Anthropic ephemeral_1h_input_tokens). When supplied, the 5m and 1h buckets sum to cacheCreationTokenCount. Leave null if the provider does not report a TTL split.","example":300},"isStreamed":{"type":"boolean","description":"Indicates whether this completion used streaming (true) or non-streaming/batch mode (false). Streaming completions receive tokens incrementally as they're generated, while non-streaming completions wait for the complete response. This affects how timeToFirstToken and responseTime are interpreted. Also accepted as 'streamed' (the Metering API v2.0.0 spec name); 'isStreamed' is the legacy name. Both field names bind to this property on input.","example":false}},"required":["completionStartTime","inputTokenCount","model","outputTokenCount","provider","requestDuration","requestTime","responseTime","stopReason","totalTokenCount"]},"AIAudioMetadataResource":{"type":"object","description":"The AI audio operation metadata","properties":{"transactionId":{"type":["string","null"],"description":"Unique identifier for this specific AI audio transaction. Used for deduplication, correlation with request/response pairs, and transaction lookup in Revenium analytics. If not provided, a UUID will be auto-generated. For best practices, generate a UUID in your application before making the AI call and use the same ID when submitting to Revenium. You can use either 'spanId' (recommended) or 'transactionId'.","example":"123e4567-e89b-12d3-a456-426614174000"},"traceId":{"type":["string","null"],"description":"Optional trace identifier to group multiple related AI audio calls that belong to the same overall user request or workflow. For example, if a single user query triggers multiple AI calls (e.g., transcription + translation), use the same traceId for all calls to analyze them together in Revenium's analytics. Leave null for standalone operations.","example":"123e4567-e89b-12d3-a456-426614174000"},"model":{"type":"string","description":"The AI model identifier used for this audio operation. Should match the exact model name from your AI provider (e.g., 'whisper-1', 'tts-1-hd', 'gpt-4o-realtime-preview'). This is used for cost calculation, performance analytics, and model comparison reporting in Revenium. Valid model names in Revenium for proper cost estimate can be verified using the sources/ai/models endpoint.","example":"whisper-1"},"provider":{"type":"string","description":"The underlying AI provider/vendor whose model is actually processing the request. This identifies which company's AI model is being used, regardless of how you're accessing it (direct API, proxy, or gateway). \n\nCommon values: 'OpenAI' (for Whisper, TTS), 'Anthropic', 'Google', 'AssemblyAI', 'ElevenLabs', 'Deepgram'. \n\nCustom values are accepted but may affect analytics categorization. If using Revenium middleware, this is typically auto-populated from the AI provider's API response.","example":"OpenAI"},"requestTime":{"type":"string","description":"The timestamp when your application sent the request to the AI provider, in ISO 8601 format with UTC timezone (e.g., '2025-03-02T15:04:05Z'). This is used to calculate request duration and analyze usage patterns over time. Set this to the time immediately before calling the AI provider's API.","example":"2025-03-02T15:04:05Z"},"responseTime":{"type":"string","description":"The timestamp when the AI audio operation finished, in ISO 8601 format with UTC timezone. For streaming requests, this is when the last data was received and the stream closed. For non-streaming requests, this is when the complete response was received. Used to calculate total request duration.","example":"2025-03-02T15:04:06Z"},"requestDuration":{"type":"integer","format":"int64","description":"The total duration of the AI audio request in milliseconds, from request start to completion. Calculated as (responseTime - requestTime). This includes network latency, AI processing time, and any mediation/gateway overhead. Used for performance analytics and SLA monitoring.","example":1247},"operationType":{"type":["string","null"],"description":"The type of operation performed","enum":["CHAT","GENERATE","EMBED","CLASSIFY","SUMMARIZE","TRANSLATE","OTHER","TOOL_CALL","RERANK","SEARCH","MODERATION","VISION","TRANSFORM","GUARDRAIL","AUDIO","VIDEO","IMAGE"],"example":"AUDIO"},"operationSubtype":{"type":["string","null"],"description":"Technical classification of the specific audio operation. Valid values: 'transcription', 'translation', 'synthesis', 'speech', 'tts', 'realtime'. Invalid values will be rejected with HTTP 400. Required for proper billing routing (determines per-second vs per-character vs per-token billing) - missing values are accepted with a warning.","example":"transcription"},"totalCost":{"type":["number","null"],"format":"double","description":"The total cost in USD for this audio operation. Typically leave null to let Revenium automatically calculate the total based on duration/characters and current pricing. Only provide a value if you have custom pricing agreements or want to override Revenium's cost calculation. If provided, this will override Revenium's automatic calculation.","example":0.006},"costType":{"type":"string","description":"The type of cost being tracked. Currently always 'AI' for AI audio costs. This field is used internally by Revenium to categorize different types of metered usage. You typically do not need to set this field as it defaults to 'AI'.","enum":["AI"],"example":"AI"},"organizationName":{"type":["string","null"],"description":"The name of the subscriber's organization from your system to allow Revenium to track usage & costs by company. i.e. AcmeCorp. If several subscriberIds have the same organizationName, Revenium's reporting will show usage for the entire organization broken down by subscriberId. This field is used for lookup and auto-creation of organizations in Revenium.","example":"AcmeCorp"},"subscriptionId":{"type":["string","null"],"description":"Unique identifier of the subscription from your own system that you wish to use to correlate usage between Revenium & your application.","example":"subscriptionId-456789"},"productName":{"type":["string","null"],"description":"The name of the product from your system that you wish to use to correlate usage between Revenium & your application. This field is used for lookup and auto-creation of products in Revenium.","example":"Free Trial"},"agent":{"type":["string","null"],"description":"The AI agent that is making the request","example":"marketing-agent"},"environment":{"type":["string","null"],"description":"Deployment environment where this AI audio operation was executed. Used for filtering and analyzing usage patterns across different deployment stages. Common values: 'production', 'staging', 'development', 'test'. Leave null if not tracking by environment.","example":"production"},"region":{"type":["string","null"],"description":"Cloud region or geographic location where this AI audio operation was processed. Used for analyzing latency patterns, compliance requirements, and regional cost differences. Examples: 'us-east-1', 'eu-west-1', 'ap-southeast-2'. Leave null if not tracking by region.","example":"us-east-1"},"parentTransactionId":{"type":["string","null"],"description":"Parent transaction ID for hierarchical tracing. When an AI audio operation is part of a larger workflow or spawned by another AI call, this field references the parent's spanId/transactionId. Used to build transaction trees and understand call hierarchies in complex multi-step AI workflows. Leave null for root-level transactions. You can use either 'parentSpanId' (recommended) or 'parentTransactionId'.","example":"parent-txn-123e4567-e89b-12d3-a456-426614174000"},"transactionName":{"type":["string","null"],"description":"Human-readable name for this transaction. Provides context about what this AI audio operation is doing in business terms. Examples: 'Transcribe Meeting', 'Generate Podcast Intro', 'Translate Customer Call'. Used in trace visualization for better readability. Falls back to taskType if not provided.","example":"Transcribe Meeting"},"retryNumber":{"type":["integer","null"],"format":"int32","description":"Retry attempt number for this AI audio operation. 0 indicates the first attempt (no retry), 1 indicates first retry, 2 indicates second retry, etc. Used for analyzing failure rates and retry patterns. Each retry attempt should be a separate transaction with incrementing retryNumber and the same traceId. Leave null or set to 0 for first attempts.","example":0},"traceType":{"type":["string","null"],"description":"Categorical identifier for grouping similar workflows (e.g., 'meeting_transcription', 'podcast_generation'). Enables trace-level analytics and anomaly detection within workflow cohorts. Must contain only alphanumeric characters, hyphens, and underscores. Max 128 characters. Defaults to 'uncategorized' if not provided or invalid. All transactions in the same trace must have the same traceType.","example":"audio_transcription"},"traceName":{"type":["string","null"],"description":"Human-readable label for individual trace instances (e.g., 'Weekly Standup - Week 42'). Enables finding specific workflow executions. Can contain any UTF-8 string. Max 256 characters. All transactions in the same trace must have the same traceName.","example":"Weekly Standup - Week 42"},"ticketId":{"type":["string","null"],"description":"External ticket or issue ID for cost attribution (e.g., 'JIRA-123', 'LINEAR-456'). Max 256 characters.","example":"JIRA-123","maxLength":256,"minLength":0},"squadId":{"type":["string","null"],"description":"Identifier for multi-agent framework team or squad (e.g., ARK, CrewAI). Used to group AI operations by agent team for analytics and cost tracking. Free-form string, max 256 characters.","example":"research-squad"},"squadName":{"type":["string","null"],"description":"Human-readable name for the squad type (e.g., 'Loan Processing', 'Document Analysis'). Used for display in the UI and analytics grouping. If squadId is provided without squadName, squadId will be used as the display name.","example":"Loan Processing"},"squadRole":{"type":["string","null"],"description":"The agent's role within this squad execution (e.g., 'Document Extractor', 'Credit Checker'). Used to identify the purpose of each agent's contribution to the squad workflow.","example":"Document Extractor"},"agenticJobId":{"type":["string","null"],"description":"Unique identifier for the agentic job instance. Used to correlate all AI operations within a single job execution. Should be unique per job run (e.g., UUID or meaningful ID like 'loan-123-processing').","example":"job-abc123","pattern":"^(?!types$|conversion-funnel$)[a-zA-Z0-9][a-zA-Z0-9._-]{0,254}$"},"agenticJobName":{"type":["string","null"],"description":"Human-readable name for the agentic job. Used for display in the UI and analytics grouping. If agenticJobId is provided without agenticJobName, the ID will be used as the display name.","example":"Process Loan Application"},"agenticJobType":{"type":["string","null"],"description":"Category or type of the agentic job. Normalized to lowercase on ingest to prevent data fragmentation. Used for grouping jobs by type in analytics and ROI calculations.","example":"loan-processing"},"agenticJobVersion":{"type":["string","null"],"description":"Version identifier for the job definition. Used to track job evolution and compare performance across versions.","example":"1.0.0"},"errorReason":{"type":["string","null"],"description":"Error message or reason if the AI audio operation failed. Include this field when the AI provider returns an error (e.g., audio too long, unsupported format, rate limit exceeded, content policy violation). Used for error rate analytics and debugging. Leave null for successful operations.","example":"Audio file too long"},"errorCode":{"type":["integer","null"],"format":"int32","description":"HTTP error code if the operation failed (e.g., 429, 503, 500). Used with billingSkipped to determine no-charge scenarios.","example":429},"subscriber":{"oneOf":[{"$ref":"#/components/schemas/SubscriberResource"},{"type":"null"}]},"middlewareSource":{"type":["string","null"],"description":"Identifier of the Revenium middleware package or SDK that captured and submitted this AI audio metadata. This field is AUTOMATICALLY SET by Revenium's middleware packages (e.g., 'revenium-openai-python', 'revenium-assemblyai-node'). You typically should NOT manually set this field. It is used for analytics to track which integration methods are being used and for debugging middleware-specific issues.","example":"revenium-openai-python-v1.2.3"},"modelSource":{"type":["string","null"],"description":"The routing or aggregation layer used to access the AI model. This identifies whether you're calling the AI provider directly or through an intermediary service. \n\nCommon values: 'DIRECT', 'LITELLM', 'OPENROUTER', 'PORTKEY', or provider names when calling directly. \n\nCustom values are accepted for specialized routing layers or gateways. This field is used for integration tracking and analytics.","example":"DIRECT"},"taskType":{"type":["string","null"],"description":"Optional category to group related AI tasks for cost and performance analysis. Use consistent values to compare metrics across different models or vendors performing the same type of work. Examples: 'transcription', 'tts', 'translation', 'voice-clone'. This is freeform text - choose values that match your use cases.","example":"transcription"},"durationSeconds":{"type":["number","null"],"format":"double","description":"Audio duration in seconds. Required for transcription/translation operations (duration-based billing).","example":125.5},"inputAudioTokenCount":{"type":["integer","null"],"format":"int64","description":"Number of input audio tokens (for real-time audio models like gpt-4o-realtime).","example":1500},"outputAudioTokenCount":{"type":["integer","null"],"format":"int64","description":"Number of output audio tokens (for real-time audio models).","example":2000},"characterCount":{"type":["integer","null"],"format":"int64","description":"Character count for TTS/speech operations. Required for per-character billing.","example":5000},"sampleRate":{"type":["integer","null"],"format":"int32","description":"Audio sample rate in Hz.","example":44100},"language":{"type":["string","null"],"description":"Language code (ISO 639-1) for the audio content.","example":"en"},"responseFormat":{"type":["string","null"],"description":"Response format for transcription (e.g., 'verbose_json', 'json', 'text', 'srt', 'vtt'). Note: 'verbose_json' is required to get duration from Whisper. Does not affect pricing.","example":"verbose_json"},"voice":{"type":["string","null"],"description":"TTS voice selection (e.g., 'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'). Does not affect pricing.","example":"alloy"},"speed":{"type":["number","null"],"format":"double","description":"TTS speed setting (0.25 to 4.0). Does not affect pricing.","example":1},"sourceLanguage":{"type":["string","null"],"description":"Source language for translation operations.","example":"spanish"},"targetLanguage":{"type":["string","null"],"description":"Target language for translation operations. For Whisper translate, always 'english'.","example":"english"},"audioFormat":{"type":["string","null"],"description":"Audio format (e.g., 'mp3', 'wav', 'flac', 'opus', 'aac'). Used for analytics and debugging. Does not affect pricing.","example":"mp3"},"quality":{"type":["string","null"],"description":"Quality setting for TTS (e.g., 'standard', 'hd'). HD quality (tts-1-hd) typically costs 2x standard (tts-1).","example":"hd"},"inputTokenCount":{"type":["integer","null"],"format":"int64","description":"Number of input text tokens for real-time audio models. Realtime API has different rates: text at $5/1M vs audio at $100/1M.","example":100},"outputTokenCount":{"type":["integer","null"],"format":"int64","description":"Number of output text tokens for real-time audio models. Realtime API has different rates: text output at $20/1M vs audio at $200/1M.","example":150},"inputMessages":{"type":["string","null"],"description":"Input prompts/messages for this audio operation. JSON-serialized array of messages in the same format as the LLM endpoint. Used for prompt analytics and cost attribution."},"outputResponse":{"type":["string","null"],"description":"Output response content or metadata (e.g., transcription text, generated audio URLs). Used for analytics and audit trail."},"promptsTruncated":{"type":["boolean","null"],"description":"Indicates if prompts were truncated due to size limits.","example":false},"billingUnit":{"type":"string","description":"How this operation should be billed. For audio: PER_SECOND (Whisper transcription/translation), PER_CHARACTER (TTS), or PER_TOKEN (realtime). Routes cost calculation in backend. Defaults to PER_SECOND if not specified. Use PER_MINUTE with custom pricing dimensions if needed.","enum":["PER_IMAGE","PER_MINUTE","PER_SECOND","PER_CHARACTER","PER_TOKEN","CREDITS"],"example":"PER_SECOND"},"billingSkipped":{"type":["boolean","null"],"description":"If true, backend returns $0 cost. Set for free tier, rate-limited requests, or other no-charge scenarios.","example":false},"skipReason":{"type":["string","null"],"description":"Reason why billing was skipped.","enum":["FREE_TIER","RATE_LIMITED","QUOTA_EXCEEDED","CONTENT_POLICY_VIOLATION","CAPACITY_UNAVAILABLE","SERVICE_UNAVAILABLE"],"example":"FREE_TIER"},"pricingTier":{"type":["string","null"],"description":"Pricing tier for batch discounts. BATCH = 50% discount, STANDARD = normal pricing.","enum":["STANDARD","BATCH"],"example":"STANDARD"},"requestedServiceTier":{"type":["string","null"],"description":"Service tier requested by user (e.g., 'priority', 'default', 'flex').","example":"default"},"actualServiceTier":{"type":["string","null"],"description":"Actual service tier used for billing. May differ from requested if downgraded.","example":"default"},"realtime":{"type":"boolean","description":"Whether this is a real-time/streaming audio operation (e.g., OpenAI Realtime API). Real-time operations have different pricing structures with separate audio and text token rates.","example":true}},"required":["model","provider","requestDuration","requestTime","responseTime"]},"IdempotencyInvalidKeyError":{"type":"object","description":"Returned by the idempotency filter when the `Idempotency-Key` header itself is invalid (empty, longer than 255 chars, contains non-printable ASCII, or appears more than once on the request).","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["validation_error"]},"code":{"type":"string","enum":["invalid_idempotency_key"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"IdempotencyKeyMismatchError":{"type":"object","description":"Returned when the same `Idempotency-Key` is reused with a different request body fingerprint.","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["idempotency_error"]},"code":{"type":"string","enum":["idempotency_key_mismatch"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"IdempotencyKeyInProgressError":{"type":"object","description":"Returned when a concurrent request with the same `Idempotency-Key` is still in flight. Response carries a `Retry-After` header.","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["idempotency_error"]},"code":{"type":"string","enum":["idempotency_key_in_progress"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"IdempotencyPayloadTooLargeError":{"type":"object","description":"Returned when the request body exceeds the maximum size buffered by the idempotency filter.","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["validation_error"]},"code":{"type":"string","enum":["payload_too_large"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"IdempotencyStoreUnavailableError":{"type":"object","description":"Returned when the idempotency cache backing store is temporarily unavailable.","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["idempotency_error"]},"code":{"type":"string","enum":["idempotency_store_unavailable"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"MeteringInsufficientScopeError":{"type":"object","description":"Returned when the caller's API key scope is not allowed to post to metering endpoints. Today this only fires for READ-scoped keys (`rev_rk_` prefix); METERING (`rev_mk_`), WRITE (`rev_sk_`), and legacy (`hak_`) scopes are all accepted on metering POSTs.","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["authorization_error"]},"code":{"type":"string","enum":["insufficient_scope"]},"message":{"type":"string"},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"RateLimitErrorResponse":{"type":"object","description":"Envelope returned on 429 responses.","properties":{"error":{"type":"object","description":"Rate-limit error body.","properties":{"type":{"type":"string","enum":["rate_limit_error"]},"code":{"type":"string","enum":["rate_limit_exceeded"]},"message":{"type":"string"},"bucket":{"type":"string","enum":["metering","analytics","platform"]},"doc_url":{"type":"string","format":"uri"}},"required":["type","code","message","doc_url"]}},"required":["error"]},"Link":{"type":"object","properties":{"href":{"type":"string"},"hreflang":{"type":"string"},"title":{"type":"string"},"type":{"type":"string"},"deprecation":{"type":"string"},"profile":{"type":"string"},"name":{"type":"string"},"templated":{"type":"boolean"}}},"Links":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/Link"}}},"responses":{"IdempotencyBadRequest":{"description":"Bad request. Either `invalid_idempotency_key` from the idempotency filter (canonical envelope), or a controller-level body parse / `@Valid` failure (legacy `ApiError` envelope). The two will converge to a single schema once the v2 error envelope unification lands.","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/IdempotencyInvalidKeyError"},{"$ref":"#/components/schemas/ApiError"}]}}}},"IdempotencyConflict":{"description":"Idempotency conflict. `idempotency_key_mismatch` when the same `Idempotency-Key` was reused with a different request body. `idempotency_key_in_progress` when a concurrent request with the same key is still in flight; in that case the response carries a `Retry-After` header.","headers":{"Retry-After":{"description":"Integer seconds to wait before retrying. Only present on `idempotency_key_in_progress`; absent on `idempotency_key_mismatch`.","schema":{"type":"integer","format":"int32"}}},"content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/IdempotencyKeyMismatchError"},{"$ref":"#/components/schemas/IdempotencyKeyInProgressError"}]}}}},"IdempotencyPayloadTooLarge":{"description":"Request body exceeds the maximum size buffered by the idempotency filter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdempotencyPayloadTooLargeError"}}}},"IdempotencyStoreUnavailable":{"description":"Idempotency cache backing store is temporarily unavailable. Retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IdempotencyStoreUnavailableError"}}}},"MeteringInsufficientScope":{"description":"Forbidden. The API key scope is not allowed to post to metering endpoints. Use a key with METERING (`rev_mk_`), WRITE (`rev_sk_`), or legacy (`hak_`) scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeteringInsufficientScopeError"}}}},"RateLimitExceeded":{"description":"Rate limit exceeded. Retry after the indicated delay.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/X-RateLimit-Limit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/X-RateLimit-Remaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/X-RateLimit-Reset"},"X-RateLimit-Bucket":{"$ref":"#/components/headers/X-RateLimit-Bucket"},"Retry-After":{"$ref":"#/components/headers/Retry-After"},"X-RateLimit-Limited-Reason":{"$ref":"#/components/headers/X-RateLimit-Limited-Reason"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitErrorResponse"}}}}},"headers":{"X-RateLimit-Limit":{"description":"Requests permitted in the current window for the bucket that applied to this request.","schema":{"type":"integer","format":"int32"}},"X-RateLimit-Remaining":{"description":"Requests remaining in the current window for this bucket. May be zero on the boundary request.","schema":{"type":"integer","format":"int32"}},"X-RateLimit-Reset":{"description":"Unix epoch seconds at which the current window resets and the counter returns to the bucket limit.","schema":{"type":"integer","format":"int32"}},"X-RateLimit-Bucket":{"description":"Which rate-limit bucket applied to this request.","schema":{"type":"string","enum":["metering","analytics","platform"]}},"Retry-After":{"description":"Integer seconds to wait before retrying after a 429.","schema":{"type":"integer","format":"int32"}},"X-RateLimit-Limited-Reason":{"description":"Reason the request was rate-limited.","schema":{"type":"string","enum":["bucket-rate","error-pattern"]}}},"securitySchemes":{"x-api-key":{"type":"apiKey","description":"API Key","name":"x-api-key","in":"header"}}}}