The following is copy/pasted from backend repo Any changes made here should be copied back.
Frontend API Updates - January 2026
Summary: New features for handling large document uploads, fire-and-forget processing, and queue management.
Quick Reference
| Feature | Endpoint/Parameter | Purpose |
|---|---|---|
| Fire-and-forget | POST /maintainSource with async: true |
Returns immediately with queueId |
| Skip parent storage | POST /maintainSource with skipParentStorage: true |
Faster processing for large files |
| Background processing | POST /manageQueue/process-background |
Triggers Netlify processor (15 min timeout) |
| Refresh expired items | POST /manageQueue/refresh-jwt |
Refresh JWT and reset to pending |
| My queue items | GET /manageQueue/items?user_id=mine |
List current user's submissions |
| Single item status | GET /manageQueue/items/:id |
Poll specific queue item |
1. Fire-and-Forget Document Upload
Submit documents and get an immediate response without waiting for processing.
Request
const response = await fetch(`${SUPABASE_URL}/functions/v1/maintainSource`, {
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
sourceUrl: "https://example.com/document.pdf",
sourceDate: "2026-01-01",
addDocs: true,
async: true, // Fire-and-forget mode
}),
});
const { queueId } = await response.json();
// HTTP 202 - Returns immediately
Response (HTTP 202)
{
"success": true,
"statusCode": 202,
"message": "Document queued for processing",
"queueId": "uuid-here",
"userId": "user-uuid",
"orgId": "org-id",
"sourceUrl": "https://example.com/document.pdf"
}
2. Faster Processing for Large Files
Use skipParentStorage: true to bypass parent document storage. This significantly speeds up processing for large files (10MB+).
{
sourceUrl: 'https://example.com/large-document.pdf',
sourceDate: '2026-01-01',
addDocs: true,
skipParentStorage: true // Skip parent doc storage
}
Trade-offs:
- Faster processing (no Storage bucket overhead)
- No parent document retrieval capability (vector chunks only)
- Standard 400-char chunks instead of larger parent chunks
3. Checking Queue Status
Option A: List User's Submissions (Recommended)
const response = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/items?user_id=mine`,
{ headers: { Authorization: `Bearer ${jwt}` } }
);
const { items } = await response.json();
// items = [{ id, status, created_at, edge_function_response, ... }]
Option B: Poll Specific Item
const response = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/items/${queueId}`,
{ headers: { Authorization: `Bearer ${jwt}` } }
);
const item = await response.json();
// item.status: 'pending' | 'processing' | 'completed' | 'failed'
// item.edge_function_response: results when completed
Polling with Exponential Backoff
async function pollQueueStatus(queueId, jwt, maxWaitMs = 600000) {
let delayMs = 1000;
const maxDelayMs = 30000;
const startTime = Date.now();
while (Date.now() - startTime < maxWaitMs) {
const response = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/items/${queueId}`,
{ headers: { Authorization: `Bearer ${jwt}` } }
);
const item = await response.json();
if (item.status === "completed") {
return { success: true, result: item.edge_function_response };
}
if (item.status === "failed") {
return { success: false, error: item.error_message };
}
await new Promise((r) => setTimeout(r, delayMs));
delayMs = Math.min(delayMs * 1.5, maxDelayMs);
}
throw new Error("Queue processing timeout");
}
4. Triggering Background Processing (Admin)
For admin UIs that need to trigger queue processing:
const response = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/process-background`,
{
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
batchSize: 5, // Process up to 5 items
}),
}
);
const { items_queued, queue_ids } = await response.json();
// HTTP 202 - Processing started in background
5. Refreshing Expired Queue Items
When queue items fail due to JWT expiration, refresh them with the current user's token and re-process.
Refresh and Reset to Pending
// Refresh all expired/failed items with current user's JWT
const response = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/refresh-jwt`,
{
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`, // Fresh JWT from current session
"Content-Type": "application/json",
},
body: JSON.stringify({
// Optional: refresh specific items by ID
// itemIds: ['uuid-1', 'uuid-2'],
// Optional: filter by status (default: ['expired', 'failed'])
// statusFilter: ['expired']
}),
}
);
const { refreshed, itemIds } = await response.json();
// { message: "Refreshed JWT and reset 3 items to pending", refreshed: 3, itemIds: [...] }
Typical Flow for Handling Expired Items
// 1. User sees "expired" items in queue management UI
// 2. User clicks "Refresh & Retry" button
// 3. Call refresh-jwt endpoint with current session token
const refreshResult = await fetch(
`${SUPABASE_URL}/functions/v1/manageQueue/refresh-jwt`,
{
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ statusFilter: ["expired", "failed"] }),
}
);
// 4. Items are now "pending" with fresh JWT
// 5. Trigger background processing
await fetch(`${SUPABASE_URL}/functions/v1/manageQueue/process-background`, {
method: "POST",
headers: {
Authorization: `Bearer ${jwt}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ batchSize: 10 }),
});
Note: The endpoint uses the caller's current Authorization header JWT to update the stored user_jwt in queue items.
6. Queue Item Status Values
| Status | Description |
|---|---|
pending |
Waiting to be processed |
processing |
Currently being processed |
completed |
Successfully processed |
failed |
Processing failed (may auto-retry) |
cancelled |
Manually cancelled |
expired |
Exceeded max retry attempts |
held |
Manually held, won't process |
6. Completed Item Response
When status === 'completed', the edge_function_response contains:
{
"success": true,
"statusCode": 200,
"message": "Successfully processed...",
"duration": 12500,
"processingStats": {
"parentDocs": { "deleted": 0, "added": 25 },
"vectorDocs": { "deleted": 0, "added": 150 },
"sourceDocsLoaded": 45,
"fileType": "pdf",
"loadMode": "remote"
}
}
Note: When skipParentStorage: true, parentDocs.added will always be 0.
Full Documentation
- manageQueue README - Queue management API
- maintainSource README - Document processing API