4.1 KiB
4.1 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"
}
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.