# M4 API Catalog (Core Only) Status: Active Date: 2026-03-11 Owner: Technical Lead Environment: dev ## Frontend source of truth Use this file and `docs/MILESTONES/M4/planning/m4-core-api-frontend-guide.md` for core endpoint consumption. Use `docs/MILESTONES/M4/planning/m4-v2-frontend-migration-guide.md` for actual frontend migration sequencing across v2 services. ## Related next-slice contract Verification pipeline design (attire, government ID, certification): - `docs/MILESTONES/M4/planning/m4-verification-architecture-contract.md` ## 1) Scope and purpose This catalog defines the currently implemented core backend contract for M4. ## 2) Global API rules 1. Route group in scope: `/core/*`. 2. Compatibility aliases in scope: - `POST /uploadFile` -> `POST /core/upload-file` - `POST /createSignedUrl` -> `POST /core/create-signed-url` - `POST /invokeLLM` -> `POST /core/invoke-llm` 3. Auth model: - `GET /health` is public in dev - all other routes require `Authorization: Bearer ` 4. Standard error envelope: ```json { "code": "STRING_CODE", "message": "Human readable message", "details": {}, "requestId": "optional-request-id" } ``` 5. Response header: - `X-Request-Id` ## 3) Core routes ## 3.1 Upload file 1. Method and route: `POST /core/upload-file` 2. Request format: `multipart/form-data` 3. Fields: - `file` (required) - `visibility` (`public` or `private`, optional) - `category` (optional) 4. Accepted types: - `application/pdf` - `image/jpeg` - `image/jpg` - `image/png` 5. Max size: `10 MB` (default) 6. Behavior: real upload to Cloud Storage. 7. Success `200`: ```json { "fileUri": "gs://krow-workforce-dev-private/uploads//...", "contentType": "application/pdf", "size": 12345, "bucket": "krow-workforce-dev-private", "path": "uploads//...", "requestId": "uuid" } ``` 8. Errors: - `UNAUTHENTICATED` - `INVALID_FILE_TYPE` - `FILE_TOO_LARGE` ## 3.2 Create signed URL 1. Method and route: `POST /core/create-signed-url` 2. Request: ```json { "fileUri": "gs://krow-workforce-dev-private/uploads//file.pdf", "expiresInSeconds": 300 } ``` 3. Security checks: - bucket must be allowed - path must be owned by caller (`uploads//...`) - object must exist - `expiresInSeconds <= 900` 4. Success `200`: ```json { "signedUrl": "https://storage.googleapis.com/...", "expiresAt": "2026-02-24T15:22:28.105Z", "requestId": "uuid" } ``` 5. Errors: - `VALIDATION_ERROR` - `FORBIDDEN` - `NOT_FOUND` ## 3.3 Invoke model 1. Method and route: `POST /core/invoke-llm` 2. Request: ```json { "prompt": "...", "responseJsonSchema": {}, "fileUrls": [] } ``` 3. Behavior: - real Vertex AI call - model default: `gemini-2.0-flash-001` - timeout default: `20 seconds` 4. Rate limit: - `20 requests/minute` per user (default) - when exceeded: `429 RATE_LIMITED` and `Retry-After` header 5. Success `200`: ```json { "result": {}, "model": "gemini-2.0-flash-001", "latencyMs": 367, "requestId": "uuid" } ``` 6. Errors: - `UNAUTHENTICATED` - `VALIDATION_ERROR` - `MODEL_TIMEOUT` - `MODEL_FAILED` - `RATE_LIMITED` ## 3.4 Create verification job 1. Method and route: `POST /core/verifications` 2. Auth: required 3. Request: ```json { "type": "attire", "subjectType": "worker", "subjectId": "worker_123", "fileUri": "gs://krow-workforce-dev-private/uploads//file.pdf", "rules": {} } ``` 4. Behavior: - validates `fileUri` ownership - requires file existence when `UPLOAD_MOCK=false` and `VERIFICATION_REQUIRE_FILE_EXISTS=true` - enqueues async verification 5. Success `202`: ```json { "verificationId": "ver_123", "status": "PENDING", "type": "attire", "requestId": "uuid" } ``` 6. Errors: - `UNAUTHENTICATED` - `VALIDATION_ERROR` - `FORBIDDEN` - `NOT_FOUND` ## 3.5 Get verification status 1. Method and route: `GET /core/verifications/{verificationId}` 2. Auth: required 3. Success `200`: ```json { "verificationId": "ver_123", "status": "NEEDS_REVIEW", "type": "attire", "requestId": "uuid" } ``` 4. Errors: - `UNAUTHENTICATED` - `FORBIDDEN` - `NOT_FOUND` ## 3.6 Review verification 1. Method and route: `POST /core/verifications/{verificationId}/review` 2. Auth: required 3. Request: ```json { "decision": "APPROVED", "note": "Manual review passed", "reasonCode": "MANUAL_REVIEW" } ``` 4. Success `200`: status becomes `APPROVED` or `REJECTED`. 5. Errors: - `UNAUTHENTICATED` - `VALIDATION_ERROR` - `FORBIDDEN` - `NOT_FOUND` ## 3.7 Retry verification 1. Method and route: `POST /core/verifications/{verificationId}/retry` 2. Auth: required 3. Success `202`: status resets to `PENDING`. 4. Errors: - `UNAUTHENTICATED` - `FORBIDDEN` - `NOT_FOUND` ## 3.8 Health 1. Method and route: `GET /health` 2. Success `200`: ```json { "ok": true, "service": "krow-core-api", "version": "dev", "requestId": "uuid" } ``` ## 4) Locked defaults 1. Validation library: `zod`. 2. Validation schema location: `backend/core-api/src/contracts/`. 3. Buckets: - `krow-workforce-dev-public` - `krow-workforce-dev-private` 4. Model provider: Vertex AI Gemini. 5. Max signed URL expiry: `900` seconds. 6. LLM timeout: `20000` ms. 7. LLM rate limit: `20` requests/minute/user. 8. Verification access mode default: `authenticated`. 9. Verification file existence check default: enabled (`VERIFICATION_REQUIRE_FILE_EXISTS=true`). 10. Verification attire provider default in dev: `vertex` with model `gemini-2.0-flash-lite-001`. 11. Verification government/certification providers: external adapters via configured provider URL/token.