Skip to main content
A composition act (an act, for short) is a ready-made way of arranging your subjects in the frame — a pose or interaction the platform reproduces with the people you supply. Instead of describing the whole arrangement in your prompt, you pin an act by its action_id and let it handle the composition while your prompt handles everything else. This guide covers what an act is, how to browse the catalog at GET /v1/actions, how action_id behaves on POST /v1/images, and how an act is matched to the number of subjects you send.

What a composition act is

Each act in the catalog is a small, self-describing record:
  • id — the identifier you pass as action_id on POST /v1/images. Treat it as opaque: it comes from GET /v1/actions and nowhere else.
  • name / description — human-readable labels for building a picker in your own UI.
  • supported_character_counts — the subject counts this act is built for (see Count matching). Pin the act with a matching number of subjects.
  • preview_url — a signed preview image URL served by the API (GET /v1/actions/{id}/preview). The image bytes stream through the API, so the URL always points at api.aurous-labs.com — never at a storage host. It is short-lived (about an hour) and re-minted every time you list the catalog, so fetch it fresh rather than storing it. null when the act has no preview image.

The catalog

List every act available to your team:
The response is a flat array — the catalog is small and curated, so there is no pagination. Fetch a single act by id to re-check its liveness and current supported_character_counts (which can change as the act’s reference material is updated):
An id that is unknown, not currently live, or not visible to your team returns 404 resource_not_found — the same response a nonexistent id would give, so the catalog never reveals which acts exist outside your team.

Pinning an act: the action_id tri-state

action_id on POST /v1/images has three distinct states, and the difference between “omitted” and “explicit null” is meaningful: So omitting the field opts in to automatic detection (the default behavior); sending an explicit null opts out for that one request; sending an id pins a specific act. This mirrors how you might already treat an unset field versus a deliberately-null one — here the distinction is load-bearing, so send the state you mean.

Count matching

An act declares the subject counts it supports in supported_character_counts. When you pin an act and send subjects, the number of subjects must be one of those counts:
  • Matching count — the act is applied. For example, an act whose supported_character_counts is [1, 2] accepts one or two subjects.
  • Unsupported count — the request returns 400 action_not_available, and the message names the counts the act does support (e.g. "This act supports 1 or 2 subjects; you sent 3."). Fix the request client-side — drop a subject, or pick a different act — and resubmit.
Sending an act with zero subjects is always valid and skips the count check entirely: the act renders a new person described by your prompt. This is the one case where supported_character_counts does not apply. The count that is matched against supported_character_counts is the number of subject entries — one per element of subjects[], plus the folded legacy character_id / reference_image_urls (each folds into a single entry). Every character subject counts as one, and every reference subject counts as one regardless of how many image_urls it carries — a reference subject with three images is still one subject for count matching. So an act whose supported_character_counts is [1, 2] accepts one or two subject entries, whether those subjects reference one image each or several. This is a different count from the reference-image budget: across all subjects, the total number of reference images (plus the act’s own reference material) must stay within the 10-image limit, or the request returns 400 too_many_reference_images (param is subjects). Count matching is about how many subjects you send; the budget is about how many images they add up to.

Quickstart

Pin an act and compose it with two saved characters:
Poll GET /v1/images/{id} (or register a webhook endpoint) until status reaches a terminal value, same as any other generation.

Rules

action_id: null and an omitted action_id never trigger the combination rules above — they mean “detection off” and “detection on”, not “pin an act.”

The response

Every GET/POST response for a generation — and every webhook delivery, which carries the same shape — now includes an action field:
  • action echoes the act that was applied — whether you pinned it with action_id or it was detected automatically — as { id, name } and nothing more. It never carries the preview image, the reference material, or any internal selection detail.
  • action.name may be null when a display name wasn’t recorded for the act, but action.id is always present when an act was applied.
  • action is null on every generation that didn’t apply an act — plain prompt-only generations, style (lora_id) generations, context-image generations, and all video generations. It’s a new, always-present, nullable key: existing integrations that don’t read it are unaffected.

Retired styles still serve as acts

A single style in GET /v1/loras and a composition act can share the same underlying model. When that model is retired as a style, one thing changes that’s worth calling out:
  • It disappears from GET /v1/loras — it’s no longer offered as a browsable style, and automatic style matching won’t pick it. This is the one behavior change to be aware of: a style that was previously listed can drop off the list once it’s retired.
  • Its act stays in GET /v1/actions as long as the act itself is live — the actions catalog is the only place a retired model surfaces publicly.
  • An explicit lora_id you’ve already persisted for that model keeps working on POST /v1/images — retiring a style hides it from discovery but never breaks a request that names it directly.
The list at GET /v1/loras was never a stability contract, so this isn’t a breaking change — but if you cache the catalog, expect a retired style to vanish from it while everything that references it by id keeps working.

Estimates

POST /v1/images/estimate mirrors the create path: pin an action_id and it runs the identical act gates — the existence/visibility check (unknown → 404 resource_not_found) and, when subjects are present, the count check (unsupported → 400 action_not_available) — without dispatching or charging. Acts don’t change the price (their reference material is free), so an act estimate quotes the standard single-image rate. As with any estimate, inline https:// reference URLs are validated for shape but never fetched — a URL-specific problem only surfaces at create.

Where to next?