{"path":"docs/wiki/API-Reference.md","size":8915,"locked":false,"binary":false,"truncated":false,"content":"# API Reference\n\nThe Mappers API server (`apps/api-server/`) exposes a REST API for managing escrow jobs, submitting deliverables, and querying aggregate statistics. All endpoints are prefixed with `/api`.\n\n**Base URL (local):** `http://localhost:3000/api`\n\n---\n\n## Authentication\n\nThe API currently does not require authentication. All endpoints are publicly accessible.\n\n---\n\n## Endpoints\n\n### Health Check\n\n```\nGET /api/health\n```\n\nReturns server health status.\n\n**Response:**\n```json\n{\n  \"status\": \"ok\"\n}\n```\n\n---\n\n### List Jobs\n\n```\nGET /api/jobs\n```\n\nReturns all registered escrow jobs, ordered by creation date.\n\n**Query Parameters:**\n\n| Parameter | Type | Description |\n|---|---|---|\n| `status` | `\"pending\" \\| \"completed\" \\| \"cancelled\"` | Filter by job status |\n| `clientPubkey` | `string` | Filter by client wallet address |\n\nBoth filters can be combined. When both are provided, only jobs matching **both** conditions are returned.\n\n**Response:**\n```json\n[\n  {\n    \"id\": 1,\n    \"jobId\": \"project-alpha-001\",\n    \"clientPubkey\": \"ABC...xyz\",\n    \"freelancerPubkey\": \"DEF...uvw\",\n    \"oraclePubkey\": \"GHI...rst\",\n    \"amountLamports\": \"5000000000\",\n    \"status\": \"pending\",\n    \"description\": \"Build a landing page\",\n    \"acceptanceCriteria\": \"[\\\"Responsive\\\",\\\"Fast load\\\"]\",\n    \"txSig\": null,\n    \"createdAt\": \"2026-01-15T10:30:00.000Z\",\n    \"updatedAt\": \"2026-01-15T10:30:00.000Z\"\n  }\n]\n```\n\n**Examples:**\n```bash\n# All jobs\ncurl http://localhost:3000/api/jobs\n\n# Only pending jobs\ncurl http://localhost:3000/api/jobs?status=pending\n\n# Jobs by a specific client\ncurl http://localhost:3000/api/jobs?clientPubkey=ABC...xyz\n\n# Pending jobs by a specific client\ncurl http://localhost:3000/api/jobs?status=pending&clientPubkey=ABC...xyz\n```\n\n---\n\n### Create Job\n\n```\nPOST /api/jobs\n```\n\nRegister a new escrow job in the database. This should be called after the on-chain `initialize_job` transaction is confirmed, to mirror the on-chain state for efficient querying.\n\n**Request Body:**\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `jobId` | `string` | Yes | Unique job identifier (max 32 chars) |\n| `clientPubkey` | `string` | Yes | Client wallet address |\n| `freelancerPubkey` | `string` | Yes | Freelancer wallet address |\n| `oraclePubkey` | `string` | Yes | Oracle authority address |\n| `amountLamports` | `string` | Yes | Escrowed amount in lamports (as string for u64 safety) |\n| `description` | `string` | No | Job description |\n| `acceptanceCriteria` | `string[]` | No | List of criteria for AI evaluation |\n\n**Example:**\n```bash\ncurl -X POST http://localhost:3000/api/jobs \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"jobId\": \"project-alpha-001\",\n    \"clientPubkey\": \"ABC...xyz\",\n    \"freelancerPubkey\": \"DEF...uvw\",\n    \"oraclePubkey\": \"GHI...rst\",\n    \"amountLamports\": \"5000000000\",\n    \"description\": \"Build a landing page with hero section\",\n    \"acceptanceCriteria\": [\"Responsive design\", \"Contact form works\"]\n  }'\n```\n\n**Response (201):**\n```json\n{\n  \"id\": 1,\n  \"jobId\": \"project-alpha-001\",\n  \"clientPubkey\": \"ABC...xyz\",\n  \"freelancerPubkey\": \"DEF...uvw\",\n  \"oraclePubkey\": \"GHI...rst\",\n  \"amountLamports\": \"5000000000\",\n  \"status\": \"pending\",\n  \"description\": \"Build a landing page with hero section\",\n  \"acceptanceCriteria\": \"[\\\"Responsive design\\\",\\\"Contact form works\\\"]\",\n  \"txSig\": null,\n  \"createdAt\": \"2026-01-15T10:30:00.000Z\",\n  \"updatedAt\": \"2026-01-15T10:30:00.000Z\"\n}\n```\n\n---\n\n### Get Job\n\n```\nGET /api/jobs/:jobId\n```\n\nFetch a single job by its ID.\n\n**Response (200):**\n```json\n{\n  \"id\": 1,\n  \"jobId\": \"project-alpha-001\",\n  \"clientPubkey\": \"ABC...xyz\",\n  ...\n}\n```\n\n**Response (404):**\n```json\n{\n  \"error\": \"Job not found\"\n}\n```\n\n---\n\n### Update Job\n\n```\nPATCH /api/jobs/:jobId\n```\n\nUpdate a job's status, transaction signature, or description.\n\n**Request Body:**\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `status` | `\"pending\" \\| \"completed\" \\| \"cancelled\"` | No | New status |\n| `txSig` | `string` | No | Transaction signature |\n| `description` | `string` | No | Updated description |\n\nAll fields are optional. Only provided fields are updated. Empty strings are valid values (e.g., to clear a description).\n\n**Example:**\n```bash\ncurl -X PATCH http://localhost:3000/api/jobs/project-alpha-001 \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"status\": \"completed\",\n    \"txSig\": \"5KtP...abc\"\n  }'\n```\n\n**Response (200):** Updated job object.\n\n**Response (404):**\n```json\n{\n  \"error\": \"Job not found\"\n}\n```\n\n---\n\n### Submit Deliverable\n\n```\nPOST /api/jobs/:jobId/submit\n```\n\nSubmit a freelancer's deliverable for AI verification. This proxies the request to the oracle middleware, which triggers the dual-model consensus pipeline.\n\n**Request Body:**\n\n| Field | Type | Required | Description |\n|---|---|---|---|\n| `description` | `string` | Yes | Original job brief |\n| `acceptanceCriteria` | `string[]` | Yes | Criteria the deliverable must meet |\n| `deliverable` | `string` | Yes | The deliverable content or reference |\n| `deliverableType` | `\"url\" \\| \"ipfs\" \\| \"text\" \\| \"json\"` | Yes | Type of deliverable |\n\n**Example:**\n```bash\ncurl -X POST http://localhost:3000/api/jobs/project-alpha-001/submit \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"description\": \"Build a landing page with hero section\",\n    \"acceptanceCriteria\": [\"Responsive design\", \"Contact form works\"],\n    \"deliverable\": \"https://my-project.vercel.app\",\n    \"deliverableType\": \"url\"\n  }'\n```\n\n**Response (200) — Consensus reached:**\n```json\n{\n  \"success\": true,\n  \"jobId\": \"project-alpha-001\",\n  \"outcome\": \"RELEASE\",\n  \"txSig\": \"5KtP...abc\",\n  \"error\": null\n}\n```\n\n**Response (503) — Oracle unreachable:**\n```json\n{\n  \"success\": false,\n  \"jobId\": \"project-alpha-001\",\n  \"outcome\": null,\n  \"txSig\": null,\n  \"error\": \"Oracle is not reachable. Ensure the oracle middleware is running with valid API keys.\"\n}\n```\n\n---\n\n### Get Statistics\n\n```\nGET /api/stats\n```\n\nReturns aggregate statistics across all jobs.\n\n**Response:**\n```json\n{\n  \"total\": 42,\n  \"pending\": 8,\n  \"completed\": 30,\n  \"cancelled\": 4,\n  \"totalEscrowedLamports\": \"40000000000\"\n}\n```\n\n`totalEscrowedLamports` represents the sum of all currently pending escrows (as a string for u64 safety).\n\n---\n\n### Oracle Health Proxy\n\n```\nGET /api/oracle/health\n```\n\nProxies the oracle's health endpoint. Useful for the dashboard to check oracle connectivity without needing to know the oracle's direct URL.\n\n**Response (200):**\n```json\n{\n  \"status\": \"ok\",\n  \"pendingJobs\": 3,\n  \"timestamp\": \"2026-01-15T10:30:00.000Z\"\n}\n```\n\n**Response (503) — Oracle unreachable:**\n```json\n{\n  \"status\": \"unreachable\",\n  \"pendingJobs\": 0,\n  \"timestamp\": \"2026-01-15T10:30:00.000Z\"\n}\n```\n\n---\n\n## Error Responses\n\nAll error responses follow a consistent format:\n\n```json\n{\n  \"error\": \"Human-readable error message\"\n}\n```\n\n| Status | Meaning |\n|---|---|\n| 400 | Invalid request (validation failure) |\n| 404 | Resource not found |\n| 500 | Internal server error |\n| 503 | Oracle service unavailable |\n\n---\n\n## Data Types\n\n### Job Object\n\n| Field | Type | Description |\n|---|---|---|\n| `id` | `number` | Auto-increment database ID |\n| `jobId` | `string` | Unique job identifier (matches on-chain) |\n| `clientPubkey` | `string` | Client Solana wallet address |\n| `freelancerPubkey` | `string` | Freelancer Solana wallet address |\n| `oraclePubkey` | `string` | Oracle authority address |\n| `amountLamports` | `string` | Escrowed amount (string for u64 precision) |\n| `status` | `string` | `\"pending\"`, `\"completed\"`, or `\"cancelled\"` |\n| `description` | `string \\| null` | Job description |\n| `acceptanceCriteria` | `string \\| null` | JSON-encoded array of criteria |\n| `txSig` | `string \\| null` | Most recent transaction signature |\n| `createdAt` | `string` | ISO 8601 timestamp |\n| `updatedAt` | `string` | ISO 8601 timestamp |\n\n### Amount Representation\n\nAmounts are always represented as **strings** in the API to preserve u64 precision. JavaScript's `Number` type loses precision above `2^53 - 1` (approximately 9,007,199 SOL). The string representation ensures no information is lost.\n\n---\n\n## Using the Generated React Client\n\nThe `@workspace/api-client-react` package provides type-safe TanStack Query hooks generated from the OpenAPI spec:\n\n```typescript\nimport { useListJobs, useGetJob, useCreateJob, useSubmitDeliverable } from \"@workspace/api-client-react\";\nimport { setBaseUrl } from \"@workspace/api-client-react\";\n\n// Configure base URL (for non-same-origin deployments)\nsetBaseUrl(\"http://localhost:3000\");\n\n// In your React component:\nfunction JobList() {\n  const { data: jobs, isLoading } = useListJobs({ status: \"pending\" });\n\n  if (isLoading) return <div>Loading...</div>;\n  return jobs?.map(job => <div key={job.jobId}>{job.jobId}</div>);\n}\n```\n\nSee the [SDK Reference](SDK-Reference.md) for the on-chain client, or [Getting Started](Getting-Started.md) to run the server locally.\n"}