defmodule ArcadiaCloudWeb.IntegrationsController do @moduledoc """ Inbound integration hooks from sibling Sky AI services. `llm_usage` receives `llm_usage_recorded` events from arcadia-llm-gateway — one per billable LLM request — and stores them for the monthly invoice rollup. platform-admin only (the gateway authenticates with a service JWT carrying that role). """ use ArcadiaCloudWeb, :controller alias ArcadiaCloud.LlmUsage def llm_usage(conn, params) do with :ok <- require_platform_admin(conn) do case LlmUsage.record_event(translate(params)) do {:ok, :recorded} -> conn |> put_status(:created) |> json(%{status: "recorded"}) {:ok, :duplicate} -> json(conn, %{status: "duplicate"}) {:error, changeset} -> conn |> put_status(:unprocessable_entity) |> json(%{error: errors(changeset)}) end end end # Maps the gateway's wire payload onto the LlmUsageEvent schema. defp translate(params) do %{ gateway_request_id: params["gateway_request_id"], tenant_id: params["tenant_id"], deployment_id: params["deployment_id"], provider: params["provider"], model: params["model"], request_kind: params["request_kind"], input_tokens: params["input_tokens"], output_tokens: params["output_tokens"], cached_input_tokens: params["cached_input_tokens"], total_tokens: params["total_tokens"], upstream_cost: params["upstream_cost_usd"], customer_charge: params["customer_charge_usd"], customer_charge_cents: params["customer_charge_cents"], markup_mode: params["markup_mode"], occurred_at: params["occurred_at"] } end defp require_platform_admin(conn) do identity = conn.assigns.current_identity if is_list(identity.roles) and "platform-admin" in identity.roles do :ok else conn |> put_status(:forbidden) |> json(%{error: "platform_admin_required"}) |> halt() end end defp errors(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Enum.reduce(opts, msg, fn {k, v}, acc -> String.replace(acc, "%{#{k}}", to_string(v)) end) end) end end