{"service":{"name":"Spendline","category":"AI spend governance / financial control layer","summary":"Spendline is the financial control layer for production AI spend. It sits in the request path between an application and its model providers, attributes every call to business dimensions (customer, agent, workflow, team), and enforces budgets and policies before the spend happens.","mechanism":"Request-path proxy. Applications change their provider base URL to Spendline and keep their own provider API keys. Attribution travels as HTTP headers.","differentiator":"Financial control, not engineering observability. Spendline blocks spend before it occurs (HTTP 402), keeps an append-only ledger suitable for finance, and closes the month like any other COGS line.","contact":"fida@spendline.ai"},"canonical_origin":"https://www.spendline.ai","request_shapes":[{"id":"openai_chat_completions","label":"OpenAI chat-completions","endpoint":"/v1/chat/completions","sdk_base_url":"https://www.spendline.ai/v1","sdk_note":"Set the OpenAI SDK baseURL/base_url to https://www.spendline.ai/v1. WITH /v1. The SDK appends /chat/completions itself.","streaming":true,"providers":["openai","google","xai","mistral","deepseek","qwen","together","fireworks","groq"],"routing":"The model name selects the provider (gpt-* → OpenAI, gemini-* → Google, grok-* → xAI, mistral-* → Mistral, …).","full_endpoint":"https://www.spendline.ai/v1/chat/completions"},{"id":"anthropic_messages","label":"Anthropic messages","endpoint":"/v1/messages","sdk_base_url":"https://www.spendline.ai","sdk_note":"Set the Anthropic SDK baseURL to https://www.spendline.ai. WITHOUT /v1. The Anthropic SDK appends /v1/messages itself. This asymmetry with the OpenAI SDK is real; do not \"fix\" it.","streaming":true,"providers":["anthropic"],"routing":"Claude models.","full_endpoint":"https://www.spendline.ai/v1/messages"},{"id":"openai_responses","label":"OpenAI Responses API","endpoint":"/v1/responses","sdk_base_url":"https://www.spendline.ai/v1","sdk_note":"Same base URL as chat-completions.","streaming":false,"streaming_note":"stream: true is rejected with a clear error. Non-streaming only.","providers":["openai"],"routing":"OpenAI models only. Built-in tools such as web_search work and their cost is included in recorded spend.","full_endpoint":"https://www.spendline.ai/v1/responses"}],"unsupported_shapes":["embeddings","image generation","audio / speech","vector or knowledge-base search","Google's native generateContent shape (use the OpenAI-compatible path instead)"],"providers":[{"key":"openai","label":"OpenAI","shape":"openai_chat_completions","also":["openai_responses"]},{"key":"anthropic","label":"Anthropic","shape":"anthropic_messages"},{"key":"google","label":"Google Gemini","shape":"openai_chat_completions"},{"key":"xai","label":"xAI","shape":"openai_chat_completions"},{"key":"mistral","label":"Mistral","shape":"openai_chat_completions"},{"key":"deepseek","label":"DeepSeek","shape":"openai_chat_completions"},{"key":"qwen","label":"Alibaba Qwen","shape":"openai_chat_completions"},{"key":"together","label":"Together AI","shape":"openai_chat_completions"},{"key":"fireworks","label":"Fireworks AI","shape":"openai_chat_completions"},{"key":"groq","label":"Groq","shape":"openai_chat_completions"}],"attribution_headers":{"auth":{"header":"x-spendline-key","value":"The Spendline API key, from env (SPENDLINE_API_KEY).","critical":"NEVER send the Spendline key as x-api-key. Anthropic uses x-api-key for the Claude provider key, so the Spendline key would be forwarded to Anthropic and rejected."},"required_when_enforced":[{"header":"x-agent-id","value":"Stable name of the bot/agent/feature making the call, e.g. support-bot.","cardinality":"One per agent. Not per request."},{"header":"x-customer-id","value":"The end customer this request is billable to.","cardinality":"PER REQUEST. A hardcoded value makes per-customer cost attribution useless, thread it from request context."},{"header":"x-spendline-tags","value":"JSON object that must include a cost-centre key: one of cost_center, costCenter, department, or team. Example: {\"team\":\"support\",\"env\":\"prod\"}","cardinality":"Per call site or per request."}],"optional":[{"header":"x-workflow-id","value":"Groups a multi-step run."},{"header":"x-step-name","value":"Labels a step within a workflow."},{"header":"x-source-route","value":"The application route that triggered the call."}]},"response_contract":[{"status":200,"meaning":"Forwarded and recorded.","agent_action":"Done."},{"status":400,"error_type":"missing_required_attribution","meaning":"Attribution enforcement is on and a required header is missing.","agent_action":"Add x-agent-id, x-customer-id and x-spendline-tags (with a cost-centre key)."},{"status":401,"meaning":"The Spendline key is missing or invalid.","agent_action":"Check SPENDLINE_API_KEY. Do NOT fall back to the provider."},{"status":402,"meaning":"A budget blocked this call before any spend occurred.","agent_action":"This is correct, intended behaviour. Surface it as an error. NEVER retry against the provider directly, that defeats the entire product."},{"status":403,"meaning":"A policy or governance rule blocked the call.","agent_action":"Surface it. NEVER route around it."},{"status":429,"meaning":"Rate limited.","agent_action":"Back off and retry."},{"status":"5xx / network error / timeout","meaning":"Spendline is unreachable or failed.","agent_action":"Retry once directly against the provider so the application stays up. This is the ONLY case where bypassing Spendline is correct."}],"capabilities":[{"id":"attribution","name":"Per-customer / agent / workflow cost attribution","detail":"Every proxied call is written to an append-only ledger (ai_calls) attributed to customer, agent, workflow, step, team and source route, with a server-controlled timestamp deciding which month it lands in."},{"id":"hierarchical_budgets","name":"Hierarchical budgets with pre-spend enforcement","detail":"Budgets nest org → team → agent → customer. Enforcement happens BEFORE the upstream call; a blocked call returns HTTP 402 and costs nothing."},{"id":"flat_budgets","name":"Account-level budget guardrails","detail":"A simpler flat monthly cap per account, evaluated on every proxied call."},{"id":"policies","name":"Policy engine","detail":"Model block lists, model allow-lists and per-model token caps, each account-wide or scoped to an agent or customer with the same scope object reroute rules use. A model block or allow-list always hard-blocks (HTTP 403); a token cap can instead be set to warn-only. A scoped policy also holds calls that carry no attribution, so a missing header is never a way around it. Supports one-time allow exceptions."},{"id":"governance","name":"Production governance rules","detail":"Environment-aware guardrails applied on top of budgets and policies."},{"id":"rerouting","name":"Cost optimizer and cross-provider rerouting","detail":"Rules can reroute a request to a cheaper or cross-provider model before it is sent, using the account's own encrypted provider keys."},{"id":"month_close","name":"AI month close and reconciliation","detail":"The ledger is designed around a finance-grade close state machine: open → ready → closed → reconciled. Closed and reconciled months are immutable; corrections ship as new ledger_adjustments rows, never as mutations of original ai_calls. Validate, close, reopen and reconcile are currently gated behind a flag not enabled in production; the ledger itself, including the append-only guarantee, is unaffected by that flag."},{"id":"margin","name":"Per-customer margin analytics","detail":"Revenue against attributed AI cost per customer: margin after AI cost, an input to gross-margin and unit-economics reporting. Other delivery costs are not included."},{"id":"alerting","name":"Anomaly detection and runaway-spend alerts","detail":"Automatic hourly budget burn-rate forecasting, plus on-demand runaway-agent anomaly detection, delivered to a Slack or Discord webhook or a custom webhook. No email delivery."},{"id":"audit","name":"Append-only audit trail","detail":"budget_audit_log and month_close_audit_log record every governance change with actor and tenant, written in the same operation as the change itself."}],"authorization":{"agent_may_alone":["Read this manifest and every public document under /agents/.","List supported providers, request shapes and models.","Decide whether Spendline fits the requirement.","Write the integration into application code (base URL + attribution headers).","Start an onboarding request that emails a human for authorization.","Poll the status of its own onboarding request.","With a Spendline key: read spend, budgets, policies and integration status."],"requires_human_authorization":[{"action":"Creating a Spendline account","why":"The human sets their own password and accepts the terms. An agent must never choose a credential for a person.","how":"The agent starts a request; the human completes signup in a browser."},{"action":"Issuing an API key to an agent","why":"A key is standing access to a financial control plane.","how":"The human explicitly approves the specific request in the browser (device-authorization flow), then the key is released once."},{"action":"Adding or changing a payment method, or subscribing to a paid plan","why":"Financial commitment.","how":"Human-only, in the dashboard. There is no API for an agent to do this."},{"action":"Storing a provider API key (OpenAI, Anthropic, …) in Spendline","why":"A provider key is a live spending credential.","how":"Human-only, in the dashboard."},{"action":"Raising or deleting a budget, or overriding a budget block","why":"It increases or removes a spending limit, the exact control the product exists to hold.","how":"Owner authority in the dashboard/API. Deliberately absent from the MCP tool surface."},{"action":"Closing, reopening or reconciling a month","why":"It changes an immutable financial period and the audit trail.","how":"Owner authority. Deliberately absent from the MCP tool surface."}],"never_permitted":["An agent obtaining the account owner/root key through any programmatic flow. Onboarding issues a scoped child key only.","An agent bypassing a 402 budget block or 403 policy block by calling the provider directly.","Any credential in a URL or query string. Spendline rejects requests whose query string names a credential."]},"documentation":{"index":"https://www.spendline.ai/agents/index.md","openapi":"https://www.spendline.ai/openapi.json","mcp":"https://www.spendline.ai/.well-known/mcp.json","full_corpus":"https://www.spendline.ai/llms-full.txt"}}