{"openapi":"3.1.0","info":{"title":"CrbonFree API","version":"1.0.0","description":"Track AI workload carbon emissions: ingest provider telemetry, calculate per-tier CO₂ with versioned factors, generate signed retirement receipts.","contact":{"name":"CrbonFree","url":"https://crbonfree.com"}},"servers":[{"url":"https://carbon-offset-backend-production.up.railway.app","description":"Production"},{"url":"http://localhost:3001","description":"Local dev"}],"tags":[{"name":"Auth","description":"Session + user metadata"},{"name":"Connections","description":"Provider API key registrations (OpenAI, Anthropic, OpenRouter, Bedrock)"},{"name":"Projects","description":"Workspace organization for telemetry"},{"name":"Usage","description":"Token/cost/carbon aggregates"},{"name":"Telemetry","description":"Event-level telemetry + emissions detail"},{"name":"Billing","description":"Receipts, audit packs, overage, periods, plan tier"},{"name":"Subscriptions","description":"Stripe subscription lifecycle + payment methods"},{"name":"Webhooks","description":"Inbound webhooks from Stripe, Clerk — not callable by SDK clients"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Clerk-issued session JWT. Obtain via `clerk.session.getToken()` in the browser SDK. Required on every endpoint except /auth/me, /health, /openapi.json, /docs, and /api/v1/webhooks/*."}},"schemas":{"HealthResponse":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"db":{"type":"string","enum":["ok","unreachable"]}},"required":["status"]},"UserPublic":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":"string","nullable":true},"accountType":{"type":"string","enum":["personal","enterprise"]},"companyName":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","email","name","accountType","companyName","createdAt"]},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string","example":"INSUFFICIENT_PERMISSIONS"},"message":{"type":"string","example":"Insufficient permissions for this organization"},"upgradeUrl":{"type":"string","example":"/billing"},"details":{"type":"object","additionalProperties":{"nullable":true}}},"required":["success","error","message"]},"ProviderConnection":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","enum":["openai","anthropic","openrouter","bedrock"]},"status":{"type":"string","enum":["pending","connected","syncing","error","revoked","disconnected"]},"projectId":{"type":"string","nullable":true,"format":"uuid"},"projectName":{"type":"string","nullable":true},"workloadId":{"type":"string","nullable":true,"format":"uuid"},"lastPolledAt":{"type":"string","nullable":true,"format":"date-time"},"consecutiveFailures":{"type":"integer","minimum":0},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","provider","status","projectId","projectName","workloadId","lastPolledAt","consecutiveFailures","createdAt","updatedAt"]},"ProjectPublic":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","example":"Default"},"isDefault":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","isDefault","createdAt","updatedAt"]},"ProjectWithUsage":{"allOf":[{"$ref":"#/components/schemas/ProjectPublic"},{"type":"object","properties":{"connectionCount":{"type":"integer","minimum":0},"last30dCo2Kg":{"type":"number","minimum":0}},"required":["connectionCount","last30dCo2Kg"]}]},"UsageSummary":{"type":"object","properties":{"range":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]},"totals":{"type":"object","properties":{"totalTokens":{"type":"number"},"promptTokens":{"type":"number"},"completionTokens":{"type":"number"},"totalCostUsd":{"type":"number"},"requestCount":{"type":"number"},"carbonKg":{"type":"number"},"electricityKwh":{"type":"number"},"offsetCostUsd":{"type":"number"}},"required":["totalTokens","promptTokens","completionTokens","totalCostUsd","requestCount","carbonKg","electricityKwh","offsetCostUsd"]},"chart":{"type":"object","properties":{"labels":{"type":"array","items":{"type":"string"}},"datasets":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"data":{"type":"array","items":{"type":"number"}}},"required":["label","data"]}}},"required":["labels","datasets"]}},"required":["range","totals","chart"]},"UsageBreakdownItem":{"type":"object","properties":{"model":{"type":"string"},"promptTokens":{"type":"number"},"completionTokens":{"type":"number"},"totalTokens":{"type":"number"},"requestCount":{"type":"number"},"costUsd":{"type":"number"},"percentage":{"type":"number"},"carbonKg":{"type":"number"},"offsetCostUsd":{"type":"number"},"electricityKwh":{"type":"number"}},"required":["model","promptTokens","completionTokens","totalTokens","requestCount","costUsd","percentage","carbonKg","offsetCostUsd","electricityKwh"]},"DailyUsageRow":{"type":"object","properties":{"date":{"type":"string"},"projectName":{"type":"string"},"promptTokens":{"type":"number"},"completionTokens":{"type":"number"},"totalTokens":{"type":"number"},"requestCount":{"type":"number"},"costUsd":{"type":"number"},"carbonKg":{"type":"number"},"energyKwh":{"type":"number"}},"required":["date","promptTokens","completionTokens","totalTokens","requestCount","costUsd","carbonKg","energyKwh"]},"DailyUsageExportRow":{"type":"object","properties":{"date":{"type":"string"},"project_name":{"type":"string"},"prompt_tokens":{"type":"number"},"completion_tokens":{"type":"number"},"total_tokens":{"type":"number"},"request_count":{"type":"number"},"cost_usd":{"type":"number"},"carbon_kg":{"type":"number"},"energy_kwh":{"type":"number"}},"required":["date","project_name","prompt_tokens","completion_tokens","total_tokens","request_count","cost_usd","carbon_kg","energy_kwh"]},"Subscription":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["incomplete","payment_method_added","active","paused","cancelled"]},"hasPaymentMethod":{"type":"boolean"},"capAmountUsd":{"type":"number"},"estimatedMonthlyCost":{"type":"number"},"cancelledAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","status","hasPaymentMethod","capAmountUsd","estimatedMonthlyCost","cancelledAt","createdAt"]},"SubscriptionEstimate":{"type":"object","properties":{"estimatedMonthlyCost":{"type":"number"},"totalTokensLast30d":{"type":"number"},"carbonKgLast30d":{"type":"number"},"isCapped":{"type":"boolean"}},"required":["estimatedMonthlyCost","totalTokensLast30d","carbonKgLast30d","isCapped"]},"PaymentMethodPublic":{"type":"object","nullable":true,"properties":{"brand":{"type":"string","nullable":true},"last4":{"type":"string"},"expiryMonth":{"type":"integer","nullable":true},"expiryYear":{"type":"integer","nullable":true}},"required":["brand","last4","expiryMonth","expiryYear"]},"InvoicePublic":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"periodStart":{"type":"string"},"periodEnd":{"type":"string"},"totalTokens":{"type":"number"},"carbonKg":{"type":"number"},"estimatedAmountUsd":{"type":"number"},"cappedAmountUsd":{"type":"number"},"status":{"type":"string"},"paidAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","periodStart","periodEnd","totalTokens","carbonKg","estimatedAmountUsd","cappedAmountUsd","status","paidAt","createdAt"]},"PaginationMeta":{"type":"object","properties":{"page":{"type":"integer","minimum":0},"limit":{"type":"integer","minimum":0,"exclusiveMinimum":true},"total":{"type":"integer","minimum":0},"totalPages":{"type":"integer","minimum":0}},"required":["page","limit","total","totalPages"]},"TelemetrySummary":{"type":"object","properties":{"total_co2_kg":{"type":"number"},"total_co2_lower_bound_kg":{"type":"number"},"total_co2_upper_bound_kg":{"type":"number"},"total_tokens":{"type":"number"},"cached_vs_uncached":{"type":"object","properties":{"uncached_tokens":{"type":"number"},"cached_tokens":{"type":"number"},"cache_creation_tokens":{"type":"number"},"cached_co2_savings_kg":{"type":"number"}},"required":["uncached_tokens","cached_tokens","cache_creation_tokens","cached_co2_savings_kg"]},"per_model":{"type":"array","items":{"type":"object","properties":{"model":{"type":"string"},"total_tokens":{"type":"number"},"co2_kg":{"type":"number"},"percentage":{"type":"number"}},"required":["model","total_tokens","co2_kg","percentage"]}},"daily_chart":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"co2_kg":{"type":"number"},"tokens":{"type":"number"}},"required":["date","co2_kg","tokens"]}},"factors_version":{"type":"string"},"period":{"type":"object","properties":{"start":{"type":"string"},"end":{"type":"string"}},"required":["start","end"]}},"required":["total_co2_kg","total_co2_lower_bound_kg","total_co2_upper_bound_kg","total_tokens","cached_vs_uncached","per_model","daily_chart","factors_version","period"]},"TelemetryEvent":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workload_id":{"type":"string"},"provider":{"type":"string"},"model":{"type":"string"},"bucket_start":{"type":"string","format":"date-time"},"bucket_end":{"type":"string","format":"date-time"},"event_timestamp":{"type":"string","format":"date-time"},"input_tokens_uncached":{"type":"number"},"input_tokens_cached":{"type":"number"},"input_tokens_cache_creation":{"type":"number"},"output_tokens":{"type":"number"},"total_tokens":{"type":"number"},"co2_kg":{"type":"number"},"co2_lower_bound_kg":{"type":"number"},"co2_upper_bound_kg":{"type":"number"},"raw_payload":{"nullable":true},"factors_version":{"type":"string"},"calculation":{"type":"object","properties":{"energy_joules":{"type":"number"},"energy_kwh":{"type":"number"},"model_tier":{"type":"string"},"pue":{"type":"number"},"grid_intensity":{"type":"number"},"uncertainty_pct":{"type":"number"}},"required":["energy_joules","energy_kwh","model_tier","pue","grid_intensity","uncertainty_pct"]}},"required":["id","workload_id","provider","model","bucket_start","bucket_end","event_timestamp","input_tokens_uncached","input_tokens_cached","input_tokens_cache_creation","output_tokens","total_tokens","co2_kg","co2_lower_bound_kg","co2_upper_bound_kg","factors_version","calculation"]},"TelemetryEventsPage":{"type":"object","properties":{"events":{"type":"array","items":{"$ref":"#/components/schemas/TelemetryEvent"}},"pagination":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total_items":{"type":"integer"},"total_pages":{"type":"integer"}},"required":["page","page_size","total_items","total_pages"]}},"required":["events","pagination"]},"TelemetryModel":{"type":"object","properties":{"provider":{"type":"string"},"model":{"type":"string"},"total_tokens":{"type":"number"},"total_co2_kg":{"type":"number"},"event_count":{"type":"integer"},"first_seen":{"type":"string"},"last_seen":{"type":"string"}},"required":["provider","model","total_tokens","total_co2_kg","event_count","first_seen","last_seen"]},"BillingPeriod":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"periodStart":{"type":"string","format":"date-time"},"periodEnd":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["open","reconciling","ready","closing","closed","failed"]},"totals":{"type":"object","properties":{"inputTokensUncached":{"type":"string"},"inputTokensCached":{"type":"string"},"inputTokensCacheCreation":{"type":"string"},"outputTokens":{"type":"string"},"requestCount":{"type":"string"},"providerCostUsd":{"type":"number"},"carbonKg":{"type":"number"},"electricityKwh":{"type":"number"}},"required":["inputTokensUncached","inputTokensCached","inputTokensCacheCreation","outputTokens","requestCount","providerCostUsd","carbonKg","electricityKwh"]},"factorsVersions":{"type":"array","items":{"type":"string"}},"planTierAtClose":{"type":"string","nullable":true,"enum":["free","starter","growth","scale","enterprise"]},"closedAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"stripeInvoiceId":{"type":"string","nullable":true},"amountChargedCents":{"type":"integer","nullable":true},"failureReason":{"type":"string","nullable":true,"enum":["payment_failed","aggregation_failed","signing_failed"]},"paidAt":{"type":"string","nullable":true,"format":"date-time"},"readyAt":{"type":"string","nullable":true,"format":"date-time"},"closingAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","periodStart","periodEnd","status","totals","factorsVersions","planTierAtClose","closedAt","createdAt","stripeInvoiceId","amountChargedCents","failureReason","paidAt","readyAt","closingAt"]},"CarbonReceipt":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"billingPeriodId":{"type":"string","format":"uuid"},"badgeSystemReceiptId":{"type":"string"},"co2Kg":{"type":"number"},"serialAllocations":{"type":"array","items":{"type":"object","properties":{"serialNumber":{"type":"string"},"totalKgCo2e":{"type":"number"}},"required":["serialNumber","totalKgCo2e"]}},"verificationUrl":{"type":"string"},"pdfUrl":{"type":"string","nullable":true},"isSigned":{"type":"boolean"},"signedAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","billingPeriodId","badgeSystemReceiptId","co2Kg","serialAllocations","verificationUrl","pdfUrl","isSigned","signedAt","createdAt"]},"AuditPack":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"organizationId":{"type":"string","format":"uuid"},"packYear":{"type":"integer"},"packMonth":{"type":"integer","minimum":1,"maximum":12},"periodStart":{"type":"string","format":"date-time"},"periodEnd":{"type":"string","format":"date-time"},"blobUrl":{"type":"string"},"manifestHash":{"type":"string"},"receiptCount":{"type":"integer","minimum":0},"fileCount":{"type":"integer","minimum":0},"totalBytes":{"type":"integer","minimum":0},"generatedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","organizationId","packYear","packMonth","periodStart","periodEnd","blobUrl","manifestHash","receiptCount","fileCount","totalBytes","generatedAt","createdAt"]},"OverageCharge":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"billingPeriodId":{"type":"string","format":"uuid"},"planTierAtClose":{"type":"string","enum":["free","starter","growth","scale","enterprise"]},"tokensOverQuota":{"type":"string"},"rateUsdPerToken":{"type":"number"},"amountCents":{"type":"integer"},"amountUsd":{"type":"number"},"stripeInvoiceId":{"type":"string","nullable":true},"status":{"type":"string","enum":["pending","billed","failed"]},"createdAt":{"type":"string","format":"date-time"},"billedAt":{"type":"string","nullable":true,"format":"date-time"}},"required":["id","billingPeriodId","planTierAtClose","tokensOverQuota","rateUsdPerToken","amountCents","amountUsd","stripeInvoiceId","status","createdAt","billedAt"]}},"parameters":{}},"paths":{"/health":{"get":{"tags":["Auth"],"summary":"Liveness probe","description":"Returns 200 if the server and DB are healthy, 503 if the DB is unreachable. No auth required. Used by Railway healthcheck.","security":[],"responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}},"503":{"description":"Degraded — DB unreachable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthResponse"}}}}}}},"/api/v1/auth/me":{"get":{"tags":["Auth"],"summary":"Get current user","description":"Returns the authenticated user, organization, and role.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current user","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/UserPublic"}},"required":["user"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Auth"],"summary":"Update profile","description":"Updates the current user profile (display name, etc.).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":255},"companyName":{"type":"string","minLength":2,"maxLength":255}}}}}},"responses":{"200":{"description":"Profile updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/UserPublic"}},"required":["user"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Auth"],"summary":"Delete account","description":"Soft-deletes the current user account.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Account deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"}},"required":["success","message"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/auth/register":{"post":{"tags":["Auth"],"summary":"Complete user registration","description":"Finalizes a new user record after first sign-in via Clerk. Idempotent.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"accountType":{"type":"string","enum":["personal","enterprise"]},"companyName":{"type":"string","minLength":2,"maxLength":255}},"required":["accountType"]}}}},"responses":{"200":{"description":"User registered (or already existed)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"user":{"$ref":"#/components/schemas/UserPublic"}},"required":["user"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/connections":{"get":{"tags":["Connections"],"summary":"List provider connections","description":"Returns all provider connections for the caller's organization.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of connections","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connections":{"type":"array","items":{"$ref":"#/components/schemas/ProviderConnection"}}},"required":["connections"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Connections"],"summary":"Register a provider connection","description":"Creates a new provider connection (admin only). Validates the supplied credentials with the provider before persisting and enqueues the initial backfill job.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"provider":{"type":"string","enum":["openai"]},"apiKey":{"type":"string","minLength":1},"projectId":{"type":"string","format":"uuid"}},"required":["provider","apiKey"]},{"type":"object","properties":{"provider":{"type":"string","enum":["anthropic"]},"apiKey":{"type":"string","minLength":1},"projectId":{"type":"string","format":"uuid"}},"required":["provider","apiKey"]},{"type":"object","properties":{"provider":{"type":"string","enum":["openrouter"]},"apiKey":{"type":"string","minLength":1},"projectId":{"type":"string","format":"uuid"}},"required":["provider","apiKey"]},{"type":"object","properties":{"provider":{"type":"string","enum":["bedrock"]},"accessKeyId":{"type":"string","minLength":1},"secretAccessKey":{"type":"string","minLength":1},"sessionToken":{"type":"string"},"regions":{"type":"array","items":{"type":"string","minLength":1},"minItems":1,"maxItems":10},"projectId":{"type":"string","format":"uuid"}},"required":["provider","accessKeyId","secretAccessKey","regions"]}]}}}},"responses":{"201":{"description":"Connection created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/ProviderConnection"}},"required":["connection"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — uniqueness violation or invalid state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/connections/{id}":{"get":{"tags":["Connections"],"summary":"Get a provider connection","description":"Returns a single connection by id, scoped to the caller's organization.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Connection details","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/ProviderConnection"}},"required":["connection"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Connections"],"summary":"Delete a provider connection","description":"Soft-deletes a connection and cancels any pending jobs (admin only).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"Connection deleted"},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/connections/{id}/sync":{"post":{"tags":["Connections"],"summary":"Trigger a manual sync","description":"Enqueues an immediate ingest job for the connection (admin only). Rejected when the connection is in error / revoked / disconnected status.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"202":{"description":"Sync job enqueued","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]}},"required":["success"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — uniqueness violation or invalid state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/connections/{id}/project":{"put":{"tags":["Connections"],"summary":"Remap connection to a different project","description":"Moves the connection's active workload to a different project within the same organization (admin only).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","format":"uuid"}},"required":["projectId"]}}}},"responses":{"200":{"description":"Connection remapped","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/ProviderConnection"}},"required":["connection"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/projects":{"get":{"tags":["Projects"],"summary":"List projects","description":"Lists projects in the active organization. With `?include=usage`, returns per-project connection count + last-30d CO₂ rollup.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["usage"]},"required":false,"name":"include","in":"query"}],"responses":{"200":{"description":"Projects list","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"projects":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/ProjectPublic"}},{"type":"array","items":{"$ref":"#/components/schemas/ProjectWithUsage"}}]}},"required":["projects"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Projects"],"summary":"Create a project","description":"Creates a new project (workspace) within the organization. Admin only.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200}},"required":["name"]}}}},"responses":{"201":{"description":"Project created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/ProjectPublic"}},"required":["project"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — uniqueness violation or invalid state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/projects/{id}":{"get":{"tags":["Projects"],"summary":"Get a project","description":"Returns a single project by id, scoped to the caller's organization.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Project","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/ProjectPublic"}},"required":["project"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"patch":{"tags":["Projects"],"summary":"Rename a project","description":"Updates the project name. Default project name cannot be changed.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200}},"required":["name"]}}}},"responses":{"200":{"description":"Project renamed","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/ProjectPublic"}},"required":["project"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — uniqueness violation or invalid state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Projects"],"summary":"Delete a project","description":"Deletes a project. Fails with 409 if any connection still maps to it.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"Project deleted"},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"Conflict — uniqueness violation or invalid state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/usage/summary":{"get":{"tags":["Usage"],"summary":"Get usage summary","description":"Returns totals (tokens/cost/carbon/energy/offset) plus a daily chart for the requested date range, optionally scoped to a project.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d","365d"],"default":"30d"},"required":false,"name":"range","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"endDate","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"projectId","in":"query"}],"responses":{"200":{"description":"Usage summary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/UsageSummary"}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/usage/breakdown":{"get":{"tags":["Usage"],"summary":"Get per-model breakdown","description":"Returns per-model token/cost/carbon/energy rollups (with `percentage` share of total tokens) for the requested date range, optionally scoped to a project.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d","365d"],"default":"30d"},"required":false,"name":"range","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"endDate","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"projectId","in":"query"}],"responses":{"200":{"description":"Per-model breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/UsageBreakdownItem"}}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/usage/daily":{"get":{"tags":["Usage"],"summary":"Get daily aggregates","description":"Returns flat daily token/cost/carbon rows for the requested date range, optionally scoped to a project.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d","365d"],"default":"30d"},"required":false,"name":"range","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"startDate","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"endDate","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"projectId","in":"query"}],"responses":{"200":{"description":"Daily aggregates","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/DailyUsageRow"}}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/usage/export":{"get":{"tags":["Usage"],"summary":"Export daily aggregates as CSV or JSON","description":"Returns a downloadable file (CSV uses RFC-4180 quoting; JSON is a flat array — no envelope). The `format` query selects the content type. When `projectId` is set, every row carries that project's name in the `project_name` column.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","enum":["7d","30d","90d","365d"],"default":"30d"},"required":false,"name":"range","in":"query"},{"schema":{"type":"string","enum":["csv","json"],"default":"csv"},"required":false,"name":"format","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"projectId","in":"query"}],"responses":{"200":{"description":"Exported file (CSV or JSON depending on `format` param)","content":{"text/csv":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DailyUsageExportRow"}}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions":{"get":{"tags":["Subscriptions"],"summary":"Get the current subscription","description":"Returns the caller's organization subscription, creating one if it does not yet exist. Open to all org members.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current subscription","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/estimate":{"get":{"tags":["Subscriptions"],"summary":"Get the estimated monthly cost","description":"Returns a 30-day lookback projection of monthly offset cost plus the underlying token + carbon aggregates and whether the projection was clamped by the spend cap.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Monthly cost estimate","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"estimate":{"$ref":"#/components/schemas/SubscriptionEstimate"}},"required":["estimate"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/cap":{"patch":{"tags":["Subscriptions"],"summary":"Update the spend cap","description":"Updates the monthly spend cap (USD). Minimum $10, two-decimal precision. Admin only.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"capAmountUsd":{"type":"number","minimum":10}},"required":["capAmountUsd"]}}}},"responses":{"200":{"description":"Spend cap updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/setup-intent":{"post":{"tags":["Subscriptions"],"summary":"Create a Stripe SetupIntent","description":"Creates a Stripe SetupIntent so the frontend can collect + confirm a payment method without immediately charging the card. Admin only.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Stripe SetupIntent client secret","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"clientSecret":{"type":"string"}},"required":["clientSecret"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/payment-method":{"post":{"tags":["Subscriptions"],"summary":"Attach a payment method","description":"Attaches a Stripe PaymentMethod (collected via SetupIntent) as the subscription's default. Admin only.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"paymentMethodId":{"type":"string","minLength":1}},"required":["paymentMethodId"]}}}},"responses":{"200":{"description":"Payment method attached","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"get":{"tags":["Subscriptions"],"summary":"Get the active payment method","description":"Returns a 4-field projection (brand, last4, expiry) of the org's default Stripe PaymentMethod, or `null` when none is attached.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Active payment method (nullable)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"paymentMethod":{"$ref":"#/components/schemas/PaymentMethodPublic"}},"required":["paymentMethod"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"delete":{"tags":["Subscriptions"],"summary":"Detach the payment method","description":"Detaches the org's default Stripe PaymentMethod and returns the updated subscription. Admin only. 404 when no PM is currently attached.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Payment method detached","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/subscribe":{"post":{"tags":["Subscriptions"],"summary":"Activate the subscription (legacy alias)","description":"Legacy endpoint that transitions an inactive subscription to active. Modern clients should attach a payment method via `POST /payment-method` instead. Admin only.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Subscription activated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cancel the subscription (legacy alias)","description":"Cancels the subscription, recording `cancelledAt`. Tier is downgraded to free as a side-effect. Admin only.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Subscription cancelled","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"subscription":{"$ref":"#/components/schemas/Subscription"}},"required":["subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/subscriptions/invoices":{"get":{"tags":["Subscriptions"],"summary":"List subscription invoices (legacy)","description":"Paginated list of the legacy per-subscription invoice rows. The newer BillingPeriod-driven flow is exposed under `/billing/periods`; this endpoint is retained for older clients. Returns an empty page when the org has no subscription.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":0,"exclusiveMinimum":true,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":10},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated invoices","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/InvoicePublic"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}},"required":["success","data","pagination"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/webhooks/stripe":{"post":{"tags":["Webhooks"],"summary":"Stripe inbound webhook","description":"Inbound webhook — not callable by SDK clients. Authenticates via provider-specific signed headers (`Stripe-Signature` / `Svix-Signature`).","security":[],"requestBody":{"required":true,"description":"Raw Stripe event payload","content":{"application/json":{"schema":{"nullable":true}}}},"responses":{"200":{"description":"Event accepted"},"400":{"description":"Invalid Stripe signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/webhooks/clerk":{"post":{"tags":["Webhooks"],"summary":"Clerk inbound webhook","description":"Inbound webhook — not callable by SDK clients. Authenticates via provider-specific signed headers (`Stripe-Signature` / `Svix-Signature`).","security":[],"requestBody":{"required":true,"description":"Raw Clerk event payload","content":{"application/json":{"schema":{"nullable":true}}}},"responses":{"200":{"description":"Event accepted"},"400":{"description":"Invalid Svix signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/telemetry/summary":{"get":{"tags":["Telemetry"],"summary":"Get telemetry summary","description":"Returns CO2 totals (with upper/lower bounds), cached-vs-uncached token split, per-model rollups, and a daily chart for the requested date range, optionally scoped to a project.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"start_date","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"end_date","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"project_id","in":"query"}],"responses":{"200":{"description":"Telemetry summary","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/TelemetrySummary"}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/telemetry/events":{"get":{"tags":["Telemetry"],"summary":"List telemetry events","description":"Returns a paginated list of per-call telemetry events with the full carbon calculation breakdown. Supports filtering by project, model, and date range. Set `skip_count=true` to skip the COUNT(*) query for cheaper pagination on large datasets.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"start_date","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"required":false,"name":"end_date","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"project_id","in":"query"},{"schema":{"type":"string","maxLength":200},"required":false,"name":"model","in":"query"},{"schema":{"type":"integer","minimum":0,"exclusiveMinimum":true,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"required":false,"name":"page_size","in":"query"},{"schema":{"type":"string","enum":["true","false"]},"required":false,"name":"skip_count","in":"query"}],"responses":{"200":{"description":"Paginated telemetry events","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/TelemetryEventsPage"}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/telemetry/models":{"get":{"tags":["Telemetry"],"summary":"List distinct telemetry models","description":"Returns the set of distinct provider/model pairs seen in the org with total tokens, total CO2, event count, and first/last-seen timestamps.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Distinct models","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/TelemetryModel"}}},"required":["models"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/periods":{"get":{"tags":["Billing"],"summary":"List billing periods","description":"Paginated list of the org's billing periods (open + closed + transient states). Open to all org members; not paywalled, so free-tier orgs can render period structure for upgrade planning.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated billing periods","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/BillingPeriod"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}},"required":["success","data","pagination"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/periods/current":{"get":{"tags":["Billing"],"summary":"Get current billing period","description":"Returns the most recent period in any status. 404 when the org has no periods yet.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Current billing period","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"period":{"$ref":"#/components/schemas/BillingPeriod"}},"required":["period"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/receipts":{"get":{"tags":["Billing"],"summary":"List carbon receipts","description":"Paginated list of carbon retirement receipts issued by badge_system. Paywalled: free-tier orgs receive 402 PAYMENT_REQUIRED with an `upgradeUrl`.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated carbon receipts","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/CarbonReceipt"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}},"required":["success","data","pagination"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/receipts/{id}":{"get":{"tags":["Billing"],"summary":"Get a carbon receipt","description":"Returns a single receipt by id, scoped to the caller's organization. Paywalled.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Carbon receipt","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"receipt":{"$ref":"#/components/schemas/CarbonReceipt"}},"required":["receipt"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/audit-packs":{"get":{"tags":["Billing"],"summary":"List audit packs","description":"Paginated list of generated audit packs (one per month, ZIP exports of receipts + manifest). Paywalled.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated audit packs","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/AuditPack"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}},"required":["success","data","pagination"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Billing"],"summary":"Generate an audit pack","description":"Synchronously generates a month's audit pack (ZIP of receipts + manifest) and returns the persisted row with a presigned blob URL. Admin only.","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"year":{"type":"integer","minimum":2024,"maximum":2100},"month":{"type":"integer","minimum":1,"maximum":12}},"required":["year","month"]}}}},"responses":{"201":{"description":"Audit pack generated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"auditPack":{"$ref":"#/components/schemas/AuditPack"}},"required":["auditPack"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/audit-packs/{id}":{"get":{"tags":["Billing"],"summary":"Get an audit pack","description":"Returns a single audit pack by id, scoped to the caller's organization. Paywalled.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Audit pack","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"auditPack":{"$ref":"#/components/schemas/AuditPack"}},"required":["auditPack"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/overage":{"get":{"tags":["Billing"],"summary":"List overage charges","description":"Paginated list of over-quota token charges (snapshotted plan tier + rate at period close). Paywalled.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"required":false,"name":"page","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Paginated overage charges","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/OverageCharge"}},"pagination":{"$ref":"#/components/schemas/PaginationMeta"}},"required":["success","data","pagination"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/overage/{id}":{"get":{"tags":["Billing"],"summary":"Get an overage charge","description":"Returns a single overage charge by id, scoped to the caller's organization. Paywalled.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","example":"00000000-0000-0000-0000-000000000001"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Overage charge","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"overageCharge":{"$ref":"#/components/schemas/OverageCharge"}},"required":["overageCharge"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"402":{"description":"Payment required — feature gated behind paid tier; clients should redirect to upgradeUrl","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}},"/api/v1/billing/plan-tier":{"get":{"tags":["Billing"],"summary":"Get the current plan tier","description":"Returns the organization's current plan tier. Read-only; open to all org members.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Plan tier","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"planTier":{"type":"string","enum":["free","starter","growth","scale","enterprise"]}},"required":["planTier"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"post":{"tags":["Billing"],"summary":"Set the plan tier","description":"Updates the organization's plan tier. Admin only. Returns the previous + current tier plus the subscription row (null when the org has no subscription).","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tier":{"type":"string","enum":["free","starter","growth","scale"]}},"required":["tier"]}}}},"responses":{"200":{"description":"Plan tier updated","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"previousTier":{"type":"string","enum":["free","starter","growth","scale","enterprise"]},"currentTier":{"type":"string","enum":["free","starter","growth","scale"]},"subscription":{"allOf":[{"$ref":"#/components/schemas/Subscription"},{"nullable":true}]}},"required":["previousTier","currentTier","subscription"]}},"required":["success","data"]}}}},"400":{"description":"Bad request — validation failed or malformed JSON body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"description":"Unauthorized — token missing, expired, or invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"403":{"description":"Forbidden — admin role required for this mutation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Too many requests — rate limit exceeded","headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until next request allowed"},"X-RateLimit-Limit":{"schema":{"type":"integer"}},"X-RateLimit-Remaining":{"schema":{"type":"integer"}},"X-RateLimit-Reset":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}}}}}