Agentic Workforce ME Developer PortalDocs 1.21 · Widget 0.5.0 · API —

Reference

Talking avatars

The agent’s face — a 2D look, a 3D model, or an animated photo — on the agent row and in the embedded widget when the embed key enables it.

A talking avatar is the agent’s face: a 2D illustration, a 3D model, or a photo the browser animates while the agent speaks. It lives on the agent row, beside emoji. It is never part of the manifest, so saving a face does not publish a new version.

The embedded widget draws that face only when the embed key’s config.avatar.enabled is true. Author it in the console on the agent’s Avatar tab, or with the routes on this page. The same face is what the Workspace and the agent lists show.

Three modes

modeWhat you get
2dA parametric illustrated face. `look` is enums plus `#rrggbb` colours. The default when an agent has no uploaded model or photo.
3dA `.glb` or `.vrm` you upload (≤ 25 MB). The server reads the file and records the lip-sync vocabulary. Switching to 3D before an upload answers `422 AVATAR_MODEL_REQUIRED`.
photoA stored portrait the browser animates from five face points. Upload requires consent. Switching to photo before an upload answers `422 AVATAR_PHOTO_REQUIRED`.

A model and a photo can both be stored. mode chooses which one is shown. Deleting the model returns the avatar to 2d and leaves a stored photo in place. Deleting the photo returns the avatar to 2d when the current mode is photo. { "avatar": null } removes the face and deletes both files.

What the widget shows

Turn it on in the key’s display config (POST / PATCH /v1/embed-keys). There is no host option that enables it — a page can only style the result.

JSON
{
  "config": {
    "avatar": { "enabled": true, "size": "stage" }
  }
}

enabled defaults to false. size is compact (header) or stage (the panel above the transcript). GET /v1/embed/config returns agent.avatar as null until the key enables it and the agent has a face. The shape is { mode, size, look, framing, model, photo }. model is present only for mode 3d ({ url, vocabulary, size_bytes }). photo is present only for mode photo ({ url, points }).

The widget lazy-loads hive-embed-avatar.js the first time a face is shown. A 3D face also loads hive-embed-avatar3d.js. The core bundle stays the same. While a voice session is live, the mouth follows that session’s audio and the pose follows listening, thinking or speaking. A typed reply drives the mouth from the streamed text. If the photo or the model fails to load, the 2D look stays up.

The bytes are GET /v1/embed/avatar/model and GET /v1/embed/avatar/photo, with the same publishable key and origin allowlist as config. The two routes share a bucket of 6 requests per minute per IP. Responses are private, max-age=86400. The ?v= on the URL is a cache-buster; the route does not read it. A key that does not show that face gets 404.

Set a 2D look

PATCH /v1/agents/:id with an admin API key. The file itself never travels in this body — only mode, look, framing, and, for a photo already uploaded, points. Omit look to keep the current one. framing.zoom is 0.5 to 2.5; framing.y is -1 to 1.

Shell
curl -sS -X PATCH "$HIVE_API_URL/v1/agents/$AGENT_ID" \
  -H "Authorization: Bearer $HIVE_API_KEY" -H "X-Tenant-Id: $HIVE_TENANT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "avatar": {
      "mode": "2d",
      "look": {
        "face": "oval",
        "skin": "#b98660",
        "hair": "none",
        "facialHair": "short_beard",
        "headwear": "ghutra_agal",
        "headwearColor": "#ffffff",
        "outfit": "kandura",
        "outfitColor": "#f7f5f0"
      },
      "framing": { "zoom": 1.1, "y": 0 }
    }
  }'

Every look field is optional. An unknown key is 400 VALIDATION. Colours are #rrggbb: skin, eyeColor, hairColor, headwearColor, outfitColor, accentColor, backgroundColor, lipColor.

FieldValues
faceoval, round, square, long, heart, diamond
eyesalmond, round, narrow, hooded, wide
browssoft, straight, arched, thick, bushy, thin
hairnone, short, side_part, curly, long, bun, buzz, wavy, ponytail, afro, bob, receding, braids
facialHairnone, stubble, short_beard, full_beard, moustache, goatee, long_beard
headwearnone, ghutra_agal, shayla, hijab, cap, shemagh, kufi, turban
outfitkandura, abaya, suit, shirt, uniform, blazer, tshirt, hoodie
glassesnone, round, square, aviator, sunglasses
backgroundnone, circle, soft
nosestraight, small, wide, long, aquiline
lipsmedium, thin, full
eyelashesnone, natural, long
ageadult, young, mature, senior
marksnone, freckles, mole, dimples
earringsnone, studs, hoops

The console Avatar tab offers named presets (an Emirati officer, an officer in a shayla, a professional, a friendly face, an elder in a shemagh, a young professional). The API stores the resulting fields. There is no preset name on the wire.

Create a look from a photo

POST /v1/agents/:id/avatar/from-photo sends one JPEG, PNG or WebP (≤ 5 MB) to the platform vision model and returns a look to preview. Nothing is saved until you PATCH it. The picture is never stored or logged. The audit row agent.avatar.from_photo and the usage kind avatar_vision_call record the model name and the byte count. No clear face answers 422 AVATAR_NO_FACE. No vision model configured answers 503 UNAVAILABLE.

Shell
curl -sS -X POST "$HIVE_API_URL/v1/agents/$AGENT_ID/avatar/from-photo" \
  -H "Authorization: Bearer $HIVE_API_KEY" -H "X-Tenant-Id: $HIVE_TENANT_ID" \
  -F "photo=@portrait.jpg;type=image/jpeg"
# → { "look": { "face": "oval", "skin": "#c9966c", … } }
# Nothing is saved. PATCH the look you accept.

Animated photo

POST /v1/agents/:id/avatar/photo stores a portrait and switches mode to photo. The multipart body carries the file, consent=true, and points — JSON for the five face points leftEye, rightEye, mouthLeft, mouthRight, chin, each {x, y} in the picture’s own 0..1 coordinates. Confirming consent is required (422 AVATAR_CONSENT_REQUIRED). Who consented and when stay on the server; clients receive photo: { url, points }. A stored 3D model is kept.

Shell
curl -sS -X POST "$HIVE_API_URL/v1/agents/$AGENT_ID/avatar/photo" \
  -H "Authorization: Bearer $HIVE_API_KEY" -H "X-Tenant-Id: $HIVE_TENANT_ID" \
  -F "photo=@portrait.jpg;type=image/jpeg" \
  -F "consent=true" \
  -F 'points={"leftEye":{"x":0.37,"y":0.40},"rightEye":{"x":0.63,"y":0.40},"mouthLeft":{"x":0.42,"y":0.62},"mouthRight":{"x":0.58,"y":0.62},"chin":{"x":0.50,"y":0.78}}'
# → 201 { "avatar": { "mode": "photo", "photo": { "url": "/v1/agents/…/avatar/photo?v=…", "points": {…} }, … } }

Members download the bytes with GET /v1/agents/:id/avatar/photo (private, max-age=86400, served only from that agent’s prefix). DELETE removes the photo (204; 404 when there is none) and, when the mode was photo, returns the avatar to 2d. Re-place the markers later with PATCH points — that requires a photo already on the agent (422 AVATAR_PHOTO_REQUIRED).

3D model

POST /v1/agents/:id/avatar/model accepts .glb or .vrm, up to 25 MB. The server checks glTF 2.0 and at least one mesh, stores the file, and switches mode to 3d. A stored photo is kept. The response is 201 with avatar and the inspection report. avatar.model is { url, vocabulary, features, size_bytes, filename }. features is { lipSync, blink, head }. Vocabulary is one of arkit, oculus, vrm, jaw, none.

Shell
curl -sS -X POST "$HIVE_API_URL/v1/agents/$AGENT_ID/avatar/model" \
  -H "Authorization: Bearer $HIVE_API_KEY" -H "X-Tenant-Id: $HIVE_TENANT_ID" \
  -F "model=@agent.vrm;type=model/gltf-binary"
# → 201 { "avatar": { "mode": "3d", "model": { "url": "…", "vocabulary": "vrm",
#      "features": { "lipSync": true, "blink": true, "head": true }, … } }, "report": {…} }

PATCH with mode: "3d" before an upload answers 422 AVATAR_MODEL_REQUIRED. Members download with GET /v1/agents/:id/avatar/model (model/gltf-binary). DELETE removes the model and sets mode to 2d. No object store configured answers 503 UNAVAILABLE.

Errors

CodeStatusWhen
AVATAR_MODEL_REQUIRED422PATCH with mode: "3d" while the agent has no uploaded model.
AVATAR_PHOTO_REQUIRED422PATCH with mode: "photo" or points while the agent has no uploaded photo.
AVATAR_CONSENT_REQUIRED422Photo upload without the multipart field consent=true.
AVATAR_NO_FACE422Create-from-photo found no clear front-facing face. Nothing is saved.
INVALID_MODEL415The upload is not a readable glTF 2.0 file with at least one mesh.
INVALID_IMAGE415The file bytes do not match the declared JPEG, PNG or WebP type.
UNSUPPORTED_TYPE415Model is not .glb / .vrm, or the photo is not JPEG, PNG or WebP.
FILE_TOO_LARGE413Model over 25 MB, or photo over 5 MB.
NO_FILE400The multipart body has no file.
VALIDATION400Face points are missing or outside 0..1, or the look contains an unknown field.
UNAVAILABLE503No object store is configured (model and photo bytes), or no vision model is configured (create-from-photo).
NOT_FOUND404Unknown agent, or a download / delete of a model or photo the agent does not have.

Audit

agent.avatar.updated on a PATCH (the mode only). agent.avatar.model.upload / agent.avatar.model.remove, agent.avatar.photo.upload / agent.avatar.photo.remove, and agent.avatar.from_photo. Upload rows record the storage key, the previous key, and the size. They never record the picture.