{"openapi":"3.1.0","info":{"title":"Fretchen AI Assistant (LLM) Service","description":"AI chat assistant, paid via x402 batch-settlement USDC payment channels.","version":"1.0.0","x-guidance":"OpenAI chat-completions body. POST / with { model, messages: [{ role, content }, ...] } and no payment header to receive a 402 with x402 batch-settlement payment requirements (accepts[]). Open/top up a payment channel per the requirements, retry with the payment header, and the service returns a standard OpenAI chat.completion object. Streaming (stream: true) is not supported. Each message is metered and settled up to a per-message price ceiling; the real cost is usage-derived and typically lower. Other standard OpenAI chat params (temperature, top_p, stop, seed, the penalties, response_format) are forwarded to the upstream model and work as normal; they are not enumerated here because the upstream owns that contract. The exceptions are stream, n and max_tokens, which are rejected with a 400 rather than ignored, because each would move cost past the fixed per-message ceiling this endpoint meters against. Tool calling is supported (see x-capabilities): send OpenAI-shaped tools, and a tool call comes back as choices[].message.tool_calls with finish_reason: \"tool_calls\" and content: null. Execute it yourself and send the result back as a role:\"tool\" message with the matching tool_call_id — this endpoint never calls a tool on your behalf, and accepts no callback or MCP server URL. Note: payment uses x402 batch-settlement (a stateful channel), so a stock OpenAI SDK cannot pay this endpoint without batch-settlement client wiring — the OpenAI shape is for body legibility, not drop-in SDK use.","contact":{"name":"fretchen","url":"https://www.fretchen.eu","email":"fretchen.dev@proton.me"}},"x-discovery":{"ownershipProofs":["0x08fd2874a7a85b7250830bf6be396953c108e197739ccc758e373036b2fe78a71ddcaf48183690b5f1d2a0049eb0af93068fb35eaaf59d266168eaeea1df357d1c"]},"x-service-type":"llm/v1","x-interop-floor":"A compatible llm/v1 agent MUST advertise at least one accepts[] entry with asset USDC on network Optimism (eip155:10) or Base (eip155:8453), scheme batch-settlement. Request/response schema is defined by this document's LLMChatRequest/LLMChatResponse. Tool calling is NOT part of the floor — see x-capabilities; a plain-chat agent that ignores tools is fully conformant. See README.md.","x-capabilities":["tools"],"servers":[{"url":"https://llm-agent.fretchen.eu"}],"tags":[{"name":"LLM","description":"AI chat assistant / text completion"},{"name":"Chat","description":"Multi-turn conversational messages"},{"name":"x402","description":"Paid via x402 batch-settlement USDC payment channels"}],"paths":{"/":{"post":{"operationId":"llmX402","summary":"Chat with the AI assistant (x402 batch-settlement USDC payment)","description":"Sends a prompt to the LLM and returns its response. Payment is settled per message via an x402 batch-settlement USDC payment channel, capped at a per-message price ceiling.","tags":["LLM","Chat","x402"],"security":[],"x-payment-info":{"protocols":["x402"],"price":{"mode":"dynamic","currency":"USD","min":"0","max":"0.009"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LLMChatRequest"}}}},"responses":{"200":{"description":"LLM response generated and payment settled successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LLMChatResponse"}}}},"400":{"description":"Request validation failed — a missing or unserved model, an empty messages array, or one of the metered params past its ceiling: stream:true, n other than 1, or any max_tokens. Body is { error: { message, type, code } }."},"402":{"description":"Payment required. Body/headers (Payment-Required, X-Payment) carry the x402 batch-settlement payment requirements to satisfy and retry with."}}}},"/openapi.json":{"get":{"operationId":"openapiSpec","summary":"This document","tags":["x402"],"responses":{"200":{"description":"This OpenAPI document.","content":{"application/json":{"schema":{"type":"object"}}}}}}}},"components":{"schemas":{"LLMChatRequest":{"type":"object","properties":{"model":{"type":"string","enum":["mistral-large-latest"],"description":"The model to use. Only the advertised model id(s) are served; others return model_not_found."},"messages":{"minItems":1,"type":"array","items":{"type":"object","properties":{"role":{"type":"string","description":"The speaker's role. Forwarded to the upstream model as sent — deliberately not restricted to the OpenAI \"system\"/\"user\"/\"assistant\" set, so a role the upstream adds later (e.g. \"tool\") works without a schema change, matching how the handler validates it."},"content":{"description":"The message text. Required except on an assistant turn that carries tool_calls, where it is null.","type":["string","null"]},"tool_calls":{"description":"Present when replaying an assistant turn that requested tool calls.","anyOf":[{"minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Echo this back as tool_call_id on the matching tool result message."},"type":{"type":"string","const":"function"},"function":{"type":"object","properties":{"name":{"type":"string"},"arguments":{"type":"string","description":"JSON-encoded arguments, as a string."}},"required":["name","arguments"],"additionalProperties":{}}},"required":["id","type","function"],"additionalProperties":{}}},{"type":"null"}]},"tool_call_id":{"description":"On a role:'tool' message, the id of the call this message answers.","type":"string"}},"required":["role"],"additionalProperties":{},"description":"One turn of the conversation."},"description":"The conversation so far. At most 65536 bytes serialized — conversation turns are input tokens charged on every hop, and this endpoint meters each message against a fixed price ceiling, so an uncapped conversation would be billed far below what it costs to serve."},"stream":{"description":"Streaming is not supported. Each message settles on its final token usage, which requires the whole completion, so stream:true is rejected rather than silently buffered.","type":"boolean","const":false},"n":{"description":"Only n=1 is supported. Each message is metered against a fixed per-message price ceiling, and additional completions multiply output tokens past it.","type":"number","const":1},"max_tokens":{"description":"Not supported. Output length is bounded by the per-message price ceiling this endpoint meters against, not by a caller-supplied limit.","not":{}},"tools":{"description":"Tool definitions offered to the model, OpenAI shape. At most 8, and at most 8192 bytes serialized — tool definitions are input tokens charged on every hop, so an uncapped array inflates the metered cost. A tool call comes back as choices[].message.tool_calls with finish_reason: \"tool_calls\"; execute it and send the result back as a role:\"tool\" message. This endpoint never calls a tool itself.","maxItems":8,"type":"array","items":{"type":"object","properties":{"type":{"type":"string","const":"function"},"function":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string"},"parameters":{"type":"object","properties":{},"additionalProperties":{}}},"required":["name"],"additionalProperties":{}}},"required":["type","function"],"additionalProperties":{}}},"tool_choice":{"description":"Whether the model may call a tool. Only \"auto\" and \"none\" are served; a forced or named choice is not.","type":"string","enum":["auto","none"]},"useDummyData":{"description":"Vendor extension (not OpenAI): forces a mock completion. Testnet networks always mock regardless. The mock is tool-aware — offered a tool with no result in the conversation yet it returns a tool_calls turn, and once a role:'tool' message is present it answers with text — so the whole tool loop can be exercised without a billed completion.","type":"boolean"},"payment":{"description":"Vendor extension: x402 payment payload, as a body fallback for clients that cannot set the PAYMENT-SIGNATURE / X-PAYMENT header. Passed through as received; validated by @x402/evm, not here."}},"required":["model","messages"],"additionalProperties":{},"description":"OpenAI chat-completions request body, plus this agent's vendor extensions. Unlisted fields are forwarded to the upstream model rather than dropped or rejected — except stream, n and max_tokens, which are rejected with a 400 because they move cost past the metered per-message ceiling."},"LLMChatResponse":{"type":"object","properties":{"id":{"type":"string"},"object":{"type":"string","const":"chat.completion"},"created":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"Unix timestamp (seconds)."},"model":{"type":"string"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"message":{"type":"object","properties":{"role":{"type":"string"},"content":{"description":"The generated reply, or null when the model is requesting a tool call.","type":["string","null"]},"tool_calls":{"description":"Present only when finish_reason is tool_calls. Execute them and send the results back as role:'tool' messages carrying the matching tool_call_id.","minItems":1,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Echo this back as tool_call_id on the matching tool result message."},"type":{"type":"string","const":"function"},"function":{"type":"object","properties":{"name":{"type":"string"},"arguments":{"type":"string","description":"JSON-encoded arguments, as a string."}},"required":["name","arguments"],"additionalProperties":{}}},"required":["id","type","function"],"additionalProperties":{}}}},"required":["role","content"],"additionalProperties":false},"finish_reason":{"type":["string","null"]}},"required":["index","message","finish_reason"],"additionalProperties":false}},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"completion_tokens":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"total_tokens":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["prompt_tokens","completion_tokens","total_tokens"],"additionalProperties":false,"description":"Token usage; the settled charge is derived from it."}},"required":["id","object","created","model","choices","usage"],"additionalProperties":false,"description":"OpenAI chat.completion object."}}}}