Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agg.market/llms.txt

Use this file to discover all available pages before exploring further.

Avatar endpoints require a signed-in user session. See Authentication for the initial sign-in flow.
Avatar upload is a two-step process: request a presigned upload URL, then upload the file directly to S3. After upload, confirm or poll for the processed avatar before updating the UI.

Step 1: Get Upload URL

// POST /users/me/avatar
const { uploadUrl, assetKey, cdnUrl } = await client.createAvatarUploadUrl("image/jpeg");

// uploadUrl = presigned S3 PUT URL (valid for 10 minutes)
// cdnUrl   = where the processed image will be served from

Step 2: Upload the Image

Upload the raw file bytes directly to the presigned URL:
const file = inputElement.files[0]; // from an <input type="file">

await fetch(uploadUrl, {
  method: "PUT",
  headers: { "Content-Type": file.type },
  body: file,
});

Step 3: Wait for Processing

The image is processed asynchronously after upload. If you want the client to explicitly finish the flow, retry updateUser({ confirmAvatar: true }) until the processed asset is ready:
async function confirmAvatar(maxAttempts = 10) {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      const profile = await client.updateUser({ confirmAvatar: true });
      if (profile.avatarUrl) {
        return profile.avatarUrl;
      }
    } catch (err: any) {
      if (err.status !== 400) throw err;
    }

    await new Promise((r) => setTimeout(r, 1000));
  }

  throw new Error("Avatar processing timed out");
}
If you prefer not to confirm explicitly, you can also poll GET /users/me until avatarUrl appears after processing finishes:
async function waitForAvatar(maxAttempts = 10) {
  for (let i = 0; i < maxAttempts; i++) {
    const profile = await client.getCurrentUser();
    if (profile.avatarUrl) {
      return profile.avatarUrl;
    }
    await new Promise((r) => setTimeout(r, 1000)); // wait 1s between polls
  }
  throw new Error("Avatar processing timed out");
}

const avatarUrl = await waitForAvatar();

Constraints

ConstraintValue
Max file size5 MB
Allowed typesJPEG, PNG, GIF, WebP
Processing timeUsually 1-3 seconds
CDN variants44px, 48px, 60px, original, raw

Removing an Avatar

await client.updateUser({ removeAvatar: true });

Error Handling

try {
  const { uploadUrl } = await client.createAvatarUploadUrl(file.type);

  const uploadRes = await fetch(uploadUrl, {
    method: "PUT",
    headers: { "Content-Type": file.type },
    body: file,
  });

  if (!uploadRes.ok) {
    throw new Error(`Upload failed: ${uploadRes.status}`);
  }

  const avatarUrl = await confirmAvatar();
  console.log("Avatar ready:", avatarUrl);
} catch (err: any) {
  if (err.status === 415) {
    console.error("Unsupported file type");
  } else {
    console.error("Avatar upload failed:", err);
  }
}