HatchedDocs
Concepts

Buddy & hatch

The avatar at the heart of Hatched — how it's created, what hatch means, and how it grows.

A buddy is the persistent companion a user gets when they join your Hatched programme. Everything else — skills, coins, streaks, badges — hangs off the buddy.

Egg and hatch

Before a buddy exists, there is an egg. Creating an egg is the first write you make to the Hatched API:

const egg = await hatched.eggs.create({
  userId: 'user_42',
});

The egg is pinned to the current config version on the customer (set during onboarding via apply-preset, or via the Dashboard) and carries any audience tags you passed. It doesn't render a visible buddy yet — it's a placeholder with pending image generation. Move the egg from waiting to ready once your own onboarding gate is complete; only ready eggs can hatch.

Hatch is the ceremony that turns an egg into a buddy:

await hatched.eggs.updateStatus(egg.eggId, 'ready');
const op = await hatched.eggs.hatch(egg.eggId);
const buddy = await hatched.operations.wait(op.operationId);

Hatching is asynchronous because image generation takes 5–20 seconds. You get an operation id back; poll it with operations.wait or listen for the buddy.hatched webhook.

One user, possibly several buddies

By default there is one buddy per (customer, external_user_id) pair. When audiences are in play, a single user can have one buddy per audience — useful when the same person plays two roles (student and teacher, for instance).

What a buddy carries

A buddy is not just a picture. It holds:

  • a config_version_id — which rulebook it lives under
  • a skills map — each skill with value and level
  • coins and any token balances
  • a list of awarded badges
  • a set of streak counters
  • an evolution stage, current image_url, and bare base_image_url
  • equipped marketplace items
  • a progression summary for XP, badges, items, and streak counters
  • an appearance block for pending or failed item compositing
  • an audience tag (if configured)

The widget reads this shape directly; your backend can mirror it via webhooks if you need your own source of truth for UX.

Appearance state

buddy.appearance separates the desired outfit from the image that is currently safe to display:

  • readyimage_url includes the rendered equipped items.
  • pending — a new composite is being generated.
  • awaiting_credits — the composite will retry after image credits are available.
  • failed — the render needs operator action or a retry.

Use desired_equipped_item_ids to know what the user wants equipped and rendered_equipped_item_ids to know what is visible in image_url. If a failed appearance has error.code === 'needs_rerender', regenerate the bare stage with buddies.rerenderAppearance(buddyId), wait for ready, then re-equip the items.

Lifecycle

Buddies are long-lived. They don't expire on their own — they evolve. When you update the rule set, existing buddies stay pinned to their old config version; you migrate them explicitly when you're ready.