6.2 KiB
6.2 KiB
M4 Core API Frontend Guide (Dev)
Status: Active
Last updated: 2026-02-24
Audience: Web and mobile frontend developers
1) Base URLs (dev)
- Core API:
https://krow-core-api-e3g6witsvq-uc.a.run.app
2) Auth requirements
- Send Firebase ID token on protected routes:
Authorization: Bearer <firebase-id-token>
- Health route is public:
GET /health
- All other routes require Firebase token.
3) Standard error envelope
{
"code": "STRING_CODE",
"message": "Human readable message",
"details": {},
"requestId": "uuid"
}
4) Core API endpoints
4.1 Upload file
- Route:
POST /core/upload-file - Alias:
POST /uploadFile - Content type:
multipart/form-data - Form fields:
file(required)visibility(optional:publicorprivate, defaultprivate)category(optional)
- Accepted file types:
application/pdfimage/jpegimage/jpgimage/png
- Max upload size:
10 MB(default) - Current behavior: real upload to Cloud Storage (not mock)
- Success
200example:
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/173...",
"contentType": "application/pdf",
"size": 12345,
"bucket": "krow-workforce-dev-private",
"path": "uploads/<uid>/173..._file.pdf",
"requestId": "uuid"
}
4.2 Create signed URL
- Route:
POST /core/create-signed-url - Alias:
POST /createSignedUrl - Request body:
{
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"expiresInSeconds": 300
}
- Security checks:
- bucket must be allowed (
krow-workforce-dev-publicorkrow-workforce-dev-private) - path must be owned by caller (
uploads/<caller_uid>/...) - object must exist
expiresInSecondsmust be<= 900
- Success
200example:
{
"signedUrl": "https://storage.googleapis.com/...",
"expiresAt": "2026-02-24T15:22:28.105Z",
"requestId": "uuid"
}
- Typical errors:
400 VALIDATION_ERROR(bad payload or expiry too high)403 FORBIDDEN(path not owned by caller)404 NOT_FOUND(object does not exist)
4.3 Invoke model
- Route:
POST /core/invoke-llm - Alias:
POST /invokeLLM - Request body:
{
"prompt": "Return JSON with keys summary and risk.",
"responseJsonSchema": {
"type": "object",
"properties": {
"summary": { "type": "string" },
"risk": { "type": "string" }
},
"required": ["summary", "risk"]
},
"fileUrls": []
}
- Current behavior: real Vertex model call (not mock)
- model:
gemini-2.0-flash-001 - timeout:
20 seconds
- Rate limit:
- per-user
20 requests/minute(default) - on limit:
429 RATE_LIMITED - includes
Retry-Afterheader
- Success
200example:
{
"result": { "summary": "text", "risk": "Low" },
"model": "gemini-2.0-flash-001",
"latencyMs": 367,
"requestId": "uuid"
}
4.4 Create verification job
- Route:
POST /core/verifications - Auth: required
- Purpose: enqueue an async verification job for an uploaded file.
- Request body:
{
"type": "attire",
"subjectType": "worker",
"subjectId": "<worker-id>",
"fileUri": "gs://krow-workforce-dev-private/uploads/<uid>/file.pdf",
"rules": {
"dressCode": "black shoes"
}
}
- Success
202example:
{
"verificationId": "ver_123",
"status": "PENDING",
"type": "attire",
"requestId": "uuid"
}
- Current machine processing behavior in dev:
attire: live vision check using Vertex Gemini Flash Lite model.government_id: third-party adapter path (falls back toNEEDS_REVIEWif provider is not configured).certification: third-party adapter path (falls back toNEEDS_REVIEWif provider is not configured).
4.5 Get verification status
- Route:
GET /core/verifications/{verificationId} - Auth: required
- Purpose: polling status from frontend.
- Success
200example:
{
"verificationId": "ver_123",
"status": "NEEDS_REVIEW",
"type": "attire",
"review": null,
"requestId": "uuid"
}
4.6 Review verification
- Route:
POST /core/verifications/{verificationId}/review - Auth: required
- Purpose: final human decision for the verification.
- Request body:
{
"decision": "APPROVED",
"note": "Manual review passed",
"reasonCode": "MANUAL_REVIEW"
}
- Success
200example:
{
"verificationId": "ver_123",
"status": "APPROVED",
"review": {
"decision": "APPROVED",
"reviewedBy": "<uid>"
},
"requestId": "uuid"
}
4.7 Retry verification
- Route:
POST /core/verifications/{verificationId}/retry - Auth: required
- Purpose: requeue verification to run again.
- Success
202example: status resets toPENDING.
5) Frontend fetch examples (web)
5.1 Signed URL request
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-e3g6witsvq-uc.a.run.app/core/create-signed-url', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
fileUri: 'gs://krow-workforce-dev-private/uploads/<uid>/file.pdf',
expiresInSeconds: 300,
}),
});
const data = await res.json();
5.2 Model request
const token = await firebaseAuth.currentUser?.getIdToken();
const res = await fetch('https://krow-core-api-e3g6witsvq-uc.a.run.app/core/invoke-llm', {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
prompt: 'Return JSON with status.',
responseJsonSchema: {
type: 'object',
properties: { status: { type: 'string' } },
required: ['status'],
},
}),
});
const data = await res.json();
6) Notes for frontend team
- Use canonical
/core/*routes for new work. - Aliases exist only for migration compatibility.
requestIdin responses should be logged client-side for debugging.- For 429 on model route, retry with exponential backoff and respect
Retry-After. - Verification routes are now available in dev under
/core/verifications*. - Current verification processing is async and returns machine statuses first (
PENDING,PROCESSING,NEEDS_REVIEW, etc.). - Full verification design and policy details:
docs/MILESTONES/M4/planning/m4-verification-architecture-contract.md.