# API Reference Arbiter provides a REST API for managing reviews, monitoring metrics, and receiving webhook events from GitHub and GitLab. ## Interactive Documentation The API provides auto-generated interactive documentation: - **Swagger UI:** `http://localhost:8000/docs` - **ReDoc:** `http://localhost:8000/redoc` - **OpenAPI Schema:** `http://localhost:8000/openapi.json` ## Base URL All API endpoints are relative to the base URL: ``` http://localhost:8000 ``` In production, use your configured domain with HTTPS. ## Authentication ### Webhook Authentication Webhooks use signature/token verification: **GitHub:** - Header: `X-Hub-Signature-256` - Format: `sha256=` - Algorithm: HMAC-SHA256 using `ARBITER_GITHUB_WEBHOOK_SECRET` **GitLab:** - Header: `X-GitLab-Token` - Format: Plain token string - Verification: Constant-time comparison with `ARBITER_GITLAB_WEBHOOK_TOKEN` ### API Authentication The REST API currently does not require authentication. For production deployments, place it behind a reverse proxy with authentication or configure network-level access controls. ## REST Endpoints ### Reviews #### List Reviews ```http GET /api/reviews ``` **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `page` | integer | 1 | Page number (1-indexed) | | `page_size` | integer | 20 | Items per page (1-100) | | `repository` | string | - | Filter by repository name | | `status` | string | - | Filter by status (pending, processing, completed, failed) | | `verdict` | string | - | Filter by verdict (approve, request_changes, comment) | | `author` | string | - | Filter by PR author | **Response:** ```json { "items": [ { "id": "abc123", "repository": "owner/repo", "pr_number": 42, "pr_title": "Add new feature", "author": "username", "status": "completed", "verdict": "request_changes", "verdict_confidence": 0.92, "finding_count": 5, "critical_count": 1, "high_count": 2, "total_cost_usd": 0.12, "created_at": "2025-06-04T10:00:00Z", "completed_at": "2025-06-04T10:02:30Z" } ], "total": 150, "page": 1, "page_size": 20, "pages": 8 } ``` #### Get Review Detail ```http GET /api/reviews/{review_id} ``` **Response:** ```json { "id": "abc123", "repository": "owner/repo", "pr_number": 42, "pr_title": "Add new feature", "base_sha": "abc1234", "head_sha": "def5678", "author": "username", "is_draft": false, "status": "completed", "verdict": "request_changes", "verdict_confidence": 0.92, "verdict_reasoning": "Critical security issue requires resolution", "total_tokens": 15000, "total_cost_usd": 0.12, "tokens_by_agent": {"security": 5000, "style": 5000, "complexity": 5000}, "cost_by_agent": {"security": 0.04, "style": 0.04, "complexity": 0.04}, "created_at": "2025-06-04T10:00:00Z", "started_at": "2025-06-04T10:00:05Z", "completed_at": "2025-06-04T10:02:30Z", "error_message": null, "findings": [ { "id": "finding-1", "agent": "security", "file": "src/auth.py", "line_start": 42, "line_end": 45, "severity": "critical", "confidence": 0.95, "title": "SQL Injection Vulnerability", "description": "User input is passed directly to SQL query", "reasoning": "String interpolation in SQL queries allows injection", "suggestion": "Use parameterized queries", "references": ["https://owasp.org/..."], "prompt_version": "security-v1.0" } ], "conflicts": [ { "id": "conflict-1", "finding_ids": ["finding-2", "finding-3"], "nature": "opposing_recommendation", "description": "Style suggests splitting function, complexity wants to keep it", "severity_weight": 0.5, "resolution": "Keep function together for readability", "winning_finding_id": "finding-3" } ] } ``` #### Get Deliberation Log ```http GET /api/reviews/{review_id}/deliberation ``` **Response:** ```json { "review_id": "abc123", "steps": [ { "id": "step-1", "step_type": "agent_start", "timestamp": "2025-06-04T10:00:10Z", "description": "Security agent started review", "details": {"agent": "security"}, "sequence": 1 }, { "id": "step-2", "step_type": "finding_added", "timestamp": "2025-06-04T10:00:45Z", "description": "Security agent found SQL injection", "details": {"finding_id": "finding-1", "severity": "critical"}, "sequence": 2 }, { "id": "step-3", "step_type": "conflict_detected", "timestamp": "2025-06-04T10:01:30Z", "description": "Detected conflict between style and complexity", "details": {"conflict_id": "conflict-1"}, "sequence": 3 }, { "id": "step-4", "step_type": "verdict_determined", "timestamp": "2025-06-04T10:02:00Z", "description": "Final verdict: request_changes", "details": {"verdict": "request_changes", "confidence": 0.92}, "sequence": 4 } ] } ``` #### Trigger Manual Review ```http POST /api/reviews ``` **Request Body:** ```json { "repository": "owner/repo", "pr_number": 42, "base_sha": "abc1234", "head_sha": "def5678", "pr_title": "Add new feature", "author": "username", "is_draft": false, "policy_name": "default", "diff_content": "diff --git a/file.py b/file.py\n..." } ``` **Response (202 Accepted):** ```json { "status": "queued", "job_id": "job-abc123", "review_id": null, "message": "Review queued with job ID job-abc123" } ``` #### Get Metrics ```http GET /api/reviews/metrics ``` **Response:** ```json { "total_reviews": 500, "completed_reviews": 485, "average_cost_usd": 0.15, "verdict_counts": { "approve": 300, "request_changes": 150, "comment": 35 }, "severity_counts": { "critical": 50, "high": 200, "medium": 500, "low": 1000, "info": 300 }, "reviews_by_day": [ {"date": "2025-06-01", "count": 15}, {"date": "2025-06-02", "count": 22}, {"date": "2025-06-03", "count": 18} ], "cost_by_agent": { "security": 25.50, "style": 20.00, "complexity": 22.00 } } ``` ### Conversations #### List Conversations ```http GET /api/conversations ``` **Query Parameters:** | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `page` | integer | 1 | Page number | | `page_size` | integer | 20 | Items per page | | `repository` | string | - | Filter by repository | | `review_id` | string | - | Filter by review ID | **Response:** ```json { "items": [ { "id": "conv-123", "review_id": "abc123", "platform": "github", "repository": "owner/repo", "pr_number": 42, "message_count": 4, "total_tokens": 2000, "total_cost_usd": 0.02, "started_at": "2025-06-04T11:00:00Z", "last_activity": "2025-06-04T11:15:00Z" } ], "total": 25, "page": 1, "page_size": 20, "pages": 2 } ``` #### Get Conversation Detail ```http GET /api/conversations/{conversation_id} ``` #### Get Conversation for Review ```http GET /api/conversations/review/{review_id} ``` Returns `null` if no conversation exists for the review. ### Health Endpoints #### Basic Health Check ```http GET /health ``` **Response:** ```json { "status": "healthy", "version": "0.5.0" } ``` #### Readiness Check ```http GET /health/ready ``` **Response:** ```json { "status": "ready", "components": { "database": {"status": "healthy"}, "redis": {"status": "healthy"}, "worker": {"status": "healthy", "queue_size": 3} } } ``` #### Liveness Probe ```http GET /health/live ``` **Response:** ```json { "status": "alive" } ``` #### Prometheus Metrics ```http GET /metrics ``` Returns Prometheus-formatted metrics. ## Webhook Endpoints ### GitHub Webhook ```http POST /webhooks/github ``` **Headers:** | Header | Description | |--------|-------------| | `X-Hub-Signature-256` | HMAC-SHA256 signature | | `X-GitHub-Event` | Event type (pull_request, issue_comment) | **Supported Events:** - `pull_request` — PR opened, synchronized, or reopened - `issue_comment` — Comment created on PR (for follow-up questions) #### Pull Request Payload ```json { "action": "opened", "pull_request": { "number": 42, "title": "Add new feature", "draft": false, "base": {"sha": "abc1234"}, "head": {"sha": "def5678"}, "user": {"login": "username"} }, "repository": { "full_name": "owner/repo" } } ``` #### Issue Comment Payload ```json { "action": "created", "issue": { "number": 42, "pull_request": {} }, "comment": { "id": 123456, "body": "Can you explain the SQL injection warning?", "user": {"login": "username"} }, "repository": { "full_name": "owner/repo" } } ``` **Responses:** ```json {"status": "queued", "job_id": "abc123", "repository": "owner/repo", "pr_number": 42} ``` ```json {"status": "ignored", "reason": "Event type 'push' not processed"} ``` ```json {"status": "duplicate", "reason": "Review already queued for this commit"} ``` ### GitLab Webhook ```http POST /webhooks/gitlab ``` **Headers:** | Header | Description | |--------|-------------| | `X-GitLab-Token` | Verification token | **Supported Events:** - `merge_request` — MR opened, reopened, or updated - `note` — Comment (note) on MR (for follow-up questions) #### Merge Request Payload ```json { "object_kind": "merge_request", "object_attributes": { "iid": 42, "title": "Add new feature", "action": "open", "target_branch": "main", "work_in_progress": false, "last_commit": {"id": "def5678"} }, "project": { "path_with_namespace": "owner/repo" }, "user": { "username": "username" } } ``` #### Note Payload ```json { "object_kind": "note", "object_attributes": { "id": 123456, "note": "Can you explain this warning?", "noteable_type": "MergeRequest" }, "merge_request": { "iid": 42 }, "project": { "path_with_namespace": "owner/repo" }, "user": { "username": "username" } } ``` ## Error Responses All endpoints return standard HTTP error codes with JSON error details: ### 400 Bad Request ```json { "detail": "Missing required fields" } ``` ### 401 Unauthorized ```json { "detail": "Invalid signature" } ``` ### 404 Not Found ```json { "detail": "Review abc123 not found" } ``` ### 422 Validation Error ```json { "detail": [ { "loc": ["body", "pr_number"], "msg": "value is not a valid integer", "type": "type_error.integer" } ] } ``` ### 500 Internal Server Error ```json { "detail": "Internal server error" } ``` ## Rate Limiting The API applies rate limiting per client IP: - Default: 60 requests per minute - Configurable via `ARBITER_API_RATE_LIMIT_PER_MINUTE` Rate limit headers are included in responses: ``` X-RateLimit-Limit: 60 X-RateLimit-Remaining: 55 X-RateLimit-Reset: 1707048120 ``` ## CORS Cross-Origin Resource Sharing is configured via `ARBITER_CORS_ORIGINS`: ```bash ARBITER_CORS_ORIGINS=["http://localhost:3000","https://dashboard.example.com"] ``` The API allows: - Specified origins - All standard headers - Credentials - GET, POST, PUT, DELETE methods