Skip to main content

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 file
  • templateGender: female or male
  • outfitMode: template or user

Supported image types

  • image/jpeg
  • image/png
  • image/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 image
  • sheet.width: width of the generated sheet image
  • sheet.height: height of the generated sheet image
  • panels.front: crop rectangle for the front view
  • panels.rightThreeQuarter: crop rectangle for the right three-quarter view
  • panels.rightProfile: crop rectangle for the right profile view
  • panels.back: crop rectangle for the back view

6. Error Responses

CodeMeaning
400Invalid request data or invalid multipart form data
401Authentication failed
411Content-Length header is required
413Request body too large or uploaded file exceeds 1 MB
415Unsupported image type
500Avatar 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 MB limit.
  • The frontend should treat sheetUrl as 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.