Avatar API
This document describes how to call the GOFA Avatar API from a user-facing web application.
The Avatar API accepts a face image and returns:
- a temporary URL for the generated avatar sheet
- the sheet dimensions
- four panel crop rectangles so the frontend can render the front, right three-quarter, right profile, and back views from the same sheet image
1. Endpoint
POST /api/avatar
Call this endpoint on your assigned GOFA client domain.
2. Authentication
This API requires a Firebase ID token for an authenticated end user.
Include the token in the request header:
Authorization: Bearer <Firebase ID Token>
This API is intended for frontend integrations that already use GOFA user authentication.
3. Request Format
Send the request as multipart/form-data.
Required fields
faceFile: user face image filetemplateGender:femaleormaleoutfitMode:templateoruser
Supported image types
image/jpegimage/pngimage/webp
File size limit
- Maximum uploaded face image size:
1 MB
4. Request Example
const idToken = await auth.currentUser?.getIdToken();
const formData = new FormData();
formData.append("faceFile", file);
formData.append("templateGender", "female");
formData.append("outfitMode", "template");
const response = await fetch("/api/avatar", {
method: "POST",
headers: {
Authorization: `Bearer ${idToken}`,
},
body: formData,
});
const data = await response.json();
5. Successful Response
200 OK
{
"sheetUrl": "https://...",
"sheet": {
"width": 1024,
"height": 1024
},
"panels": {
"front": {
"left": 20,
"top": 20,
"width": 472,
"height": 472
},
"rightThreeQuarter": {
"left": 532,
"top": 20,
"width": 472,
"height": 472
},
"rightProfile": {
"left": 20,
"top": 532,
"width": 472,
"height": 472
},
"back": {
"left": 532,
"top": 532,
"width": 472,
"height": 472
}
}
}
Response fields
sheetUrl: temporary URL of the generated avatar sheet imagesheet.width: width of the generated sheet imagesheet.height: height of the generated sheet imagepanels.front: crop rectangle for the front viewpanels.rightThreeQuarter: crop rectangle for the right three-quarter viewpanels.rightProfile: crop rectangle for the right profile viewpanels.back: crop rectangle for the back view
6. Error Responses
| Code | Meaning |
|---|---|
| 400 | Invalid request data or invalid multipart form data |
| 401 | Authentication failed |
| 411 | Content-Length header is required |
| 413 | Request body too large or uploaded file exceeds 1 MB |
| 415 | Unsupported image type |
| 500 | Avatar generation failed |
Example error body:
{
"error": "Image must be smaller than 1MB"
}
7. Frontend Rendering Strategy
The response does not return four separate image URLs.
Instead:
- the backend returns one generated sheet image URL
- the backend also returns crop rectangles for each panel
- the frontend displays the same image multiple times using different crop areas
This keeps storage usage low and avoids creating additional temporary panel files.
8. Frontend Example: Render the Avatar Sheet
<img
src={data.sheetUrl}
alt="Generated avatar sheet"
width={data.sheet.width}
height={data.sheet.height}
/>
9. Frontend Example: Render a Panel Using Canvas
function renderPanel(
canvas: HTMLCanvasElement,
image: HTMLImageElement,
rect: { left: number; top: number; width: number; height: number }
) {
const context = canvas.getContext("2d");
if (!context) {
return;
}
canvas.width = rect.width;
canvas.height = rect.height;
context.clearRect(0, 0, rect.width, rect.height);
context.drawImage(
image,
rect.left,
rect.top,
rect.width,
rect.height,
0,
0,
rect.width,
rect.height,
);
}
Example usage:
const image = new Image();
image.onload = () => {
renderPanel(frontCanvas, image, data.panels.front);
renderPanel(rightThreeQuarterCanvas, image, data.panels.rightThreeQuarter);
renderPanel(rightProfileCanvas, image, data.panels.rightProfile);
renderPanel(backCanvas, image, data.panels.back);
};
image.src = data.sheetUrl;
10. Notes
- Always call this API with a valid Firebase ID token for the signed-in user.
- Always use
multipart/form-data. - Keep the uploaded face image within the
1 MBlimit. - The frontend should treat
sheetUrlas a temporary resource and should not assume it is permanent. - The panel coordinates are based on the generated sheet and should be used together with the returned
sheetUrl.