{"openapi":"3.2.0","info":{"title":"Code Review API - AI Pull Request and Diff Reviewer API","description":"Send a diff, get structured bug/security findings: file:line, severity, fixes. Tuned code-review model. Cheaper than GPT-4 / Claude.","version":"1.0.0"},"servers":[{"url":"https://cmngo.jojapi.net"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"v1"},{"name":"health"}],"x-agent-commerce":{"catalog_url":"https://cmngo.jojapi.net/_jojapi/agent/plans","discovery_url":"https://cmngo.jojapi.net/.well-known/x402","directory_url":"https://agents.jojapi.net/apis/ro2-labs-api","docs":"https://docs.jojapi.com/consumers/agents"},"paths":{"/v1/models":{"get":{"operationId":"get_v1_models","summary":"List available models","description":"Returns available models (OpenAI-compatible).","tags":["v1"],"responses":{"200":{"description":"Model list","content":{"application/json":{"schema":{"type":"object","properties":{"object":{"type":"string","example":"list"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"llama3.1:70b"},"object":{"type":"string","example":"model"},"owned_by":{"type":"string","example":"ro2-labs"}}}}}}}}}}}},"/v1/chat/completions":{"post":{"operationId":"post_v1_chat_completions","summary":"Create chat completion","description":"Generate a response from Llama 3 70B. Fully OpenAI-compatible — use the same SDK and parameters you'd use with GPT-4o.\n\nYour data never leaves RO2 Labs infrastructure. No third-party routing. No telemetry.","tags":["v1"],"responses":{"200":{"description":"Chat completion response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","example":"chatcmpl-ro2-a7f3c2b1"},"object":{"type":"string","example":"chat.completion"},"created":{"type":"integer","example":1746763200},"model":{"type":"string","example":"llama3.1:70b"},"choices":{"type":"array","items":{"type":"object","properties":{"index":{"type":"integer"},"message":{"type":"object","properties":{"role":{"type":"string","example":"assistant"},"content":{"type":"string"}}},"finish_reason":{"type":"string","example":"stop"}}}},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"},"total_tokens":{"type":"integer"}}},"x-ro2-data-residency":{"type":"string","example":"on-prem-austin-tx"},"x-ro2-third-party-routing":{"type":"string","example":"none"}}}}}},"401":{"description":"Missing API key"},"403":{"description":"Invalid API key"},"429":{"description":"Rate limit exceeded"},"502":{"description":"Inference engine unavailable"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","description":"Conversation messages in OpenAI format.","items":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string"}}},"example":[{"role":"system","content":"You are a helpful assistant. Never transmit this data externally."},{"role":"user","content":"Summarize the key provisions of GLBA Section 501(b)."}]},"temperature":{"type":"number","minimum":0,"maximum":2,"default":0.7,"description":"Sampling temperature."},"top_p":{"type":"number","minimum":0,"maximum":1,"default":1,"description":"Nucleus sampling parameter."},"max_tokens":{"type":"integer","minimum":1,"maximum":8192,"default":2048,"description":"Maximum tokens to generate."},"stream":{"type":"boolean","default":false,"description":"Stream response as SSE events."}}},"example":{}}}}}},"/v1/review":{"post":{"operationId":"post_v1_review","summary":"Review code, return structured findings","description":"Send a unified diff (or whole files) and get structured review findings — each with\n`file`, `line`, `severity`, `issue`, and `suggestion` — plus a one-line `summary`.\n\nProvide either `diff` or `files` (if both are sent, `diff` wins). Every plan is\nreviewed by the same review-tuned model. Your code never leaves RO2 Labs\ninfrastructure — no third-party routing, no telemetry.","tags":["v1"],"responses":{"200":{"description":"Structured review result","content":{"application/json":{"schema":{"type":"object","properties":{"api_version":{"type":"string","example":"1.3.0"},"findings":{"type":"array","items":{"type":"object","properties":{"file":{"type":"string","example":"db.py"},"line":{"type":"integer","example":12},"severity":{"type":"string","enum":["critical","high","medium","low","nit"],"example":"high"},"issue":{"type":"string","example":"SQL built by string concatenation — injection risk."},"suggestion":{"type":"string","example":"Use a parameterized query."},"line_unverified":{"type":"boolean","description":"Present and true when the reported line could not be matched to a changed diff hunk."}}}},"summary":{"type":"string","description":"Severity roll-up derived from the findings actually returned, so it can never disagree with the `findings` array. Also states when findings were dropped in validation, in which case the review is inconclusive rather than clean.","example":"1 high."},"model_summary":{"type":"string","description":"The model's own one-line sentence, unvalidated. Present only when the model supplied one. It can disagree with `findings`; treat `summary` as authoritative.","example":"1 high: SQL injection."},"model_tier":{"type":"string","example":"gateway"},"parse_warning":{"type":"boolean","description":"Present and true when structured parsing failed, or when every finding the model produced failed validation; `summary` then holds the raw prose review or an inconclusive notice, and `findings` may be empty."},"truncated":{"type":"boolean","description":"Present and true when the model output hit the token cap; findings may be incomplete."},"usage":{"type":"object","properties":{"prompt_tokens":{"type":"integer"},"completion_tokens":{"type":"integer"}}},"x-ro2-data-residency":{"type":"string","example":"on-prem-austin-tx"},"x-ro2-third-party-routing":{"type":"string","example":"none"}}}}}},"400":{"description":"Neither `diff` nor `files` provided"},"401":{"description":"Missing API key"},"403":{"description":"Invalid API key"},"413":{"description":"Input exceeds the size cap"},"429":{"description":"Rate limit exceeded"},"502":{"description":"Inference engine unavailable"},"503":{"description":"Server at capacity — try again shortly"},"504":{"description":"Upstream inference timed out"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","description":"Provide either `diff` or `files`. `diff` takes precedence if both are present.","properties":{"diff":{"type":"string","description":"Unified diff text to review.","example":"diff --git a/db.py b/db.py\n--- a/db.py\n+++ b/db.py\n@@ -10,6 +10,8 @@\n+def get_user(conn, uid):\n+    return conn.execute(\"SELECT * FROM users WHERE id = \" + uid).fetchone()\n"},"files":{"type":"array","description":"Whole files to review. Used only when `diff` is absent.","items":{"type":"object","required":["path","content"],"properties":{"path":{"type":"string","example":"src/app.py"},"content":{"type":"string"}}}},"language":{"type":"string","description":"Optional language hint.","example":"python"},"context":{"type":"string","description":"Optional PR description / intent.","example":"Add a user lookup helper."}}},"example":{}}}}}},"/health":{"get":{"operationId":"get_health","summary":"Health check","description":"Returns API status and uptime.","tags":["health"],"responses":{"200":{"description":"API is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"model":{"type":"string","example":"llama3.1:70b"},"uptime":{"type":"number","example":86400.5}}}}}}}}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-JoJAPI-Key","description":"Your JoJ API key."}}}}