# Influencers (/docs/api/concepts/influencers)



An influencer is a brand-ambassador persona attached to a [project](/docs/api/concepts/projects). It has a look, a voice, a speaking style, a sense of humor, and a set of content themes. When you generate UGC-style content, the influencer is what the hook, the caption, and the narrative speak as.

Influencers aren't real people. They're synthetic personas, rendered consistently across generations so a customer's feed reads like one creator instead of a pile of LLM output. One project can have many; most projects ship with one auto-created at onboarding and add more over time.

## Where they come from [#where-they-come-from]

Two paths:

1. **Auto-created at project provision.** As soon as you `POST /v1/projects` with an `appDescription`, Layers spins up an initial influencer in the background — persona derived from brand context (voice, target audience, language). The row appears with `status: "pending"` within \~1s and flips through `training` to `status: "ready"` in \~1 minute. You don't have to do anything for this to happen; ingest endpoints are not a precondition.
2. **Created on demand.** `POST /v1/projects/:projectId/influencers` kicks off an `influencer_create` job. The body is intentionally tiny — only `gender`, `ageRange`, and `prompt` (free-text visual hint). The display name is generated server-side; `brandVoice` and `language` are inherited from the project and not accepted on this call (patch the influencer post-create to override them). See [Create an influencer](/docs/api/reference/influencers/create-influencer) for the full contract.

## Schema [#schema]

The partner-facing influencer surface is intentionally tight: identity, lifecycle, voice, and language. The portrait, persona descriptors, and reference photos are generated and managed server-side.

```json
{
  "influencerId": "inf_4a8e1bc2-3d4f-46a8-9b0c-1d2e3f4a5b6c",
  "projectId": "prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
  "name": "Nova",
  "gender": "non_binary",
  "ageRange": "young_adult",
  "brandVoice": "casual",
  "language": "en",
  "status": "ready",
  "createdAt": "2026-04-18T12:04:11.000Z",
  "updatedAt": "2026-04-18T12:04:11.000Z"
}
```

Status values: `pending | training | ready | failed`. Gender values: `male | female | non_binary` — never null; content generation requires a gender mapping.

## Voice and language [#voice-and-language]

`brandVoice` and `language` are first-class fields on the influencer — not on the content piece, the layer, or the project. The influencer is the source of truth for both.

* **`brandVoice`** picks one of six presets (`authentic | witty | professional | warm | casual | educational`) that drive tone in captions, hooks, and engagement comments. Default: `authentic`.
* **`language`** is a BCP 47 locale tag (`en`, `en-US`, `pt-BR`, `zh-Hans-CN`). Default: `en`.

To run the same persona in multiple languages — say, `Maria` in English on the US account and Spanish on the Mexico account — clone the influencer with a different `language` rather than overriding it per content piece. The clone keeps the appearance anchor and persona but renders with the new locale.

<Callout>
  Changing voice or language doesn't retroactively regenerate existing content. It only affects new generations that reference this influencer after the patch lands.
</Callout>

## Cloning [#cloning]

```http
POST /v1/influencers/:influencerId/clone
{
  "name": "Maria (ES)",
  "overrides": {
    "language": "es-MX"
  }
}
→ 202
{
  "jobId": "job_01HX9Y6K7EJ4T2ABCDEF01234",
  "kind": "influencer_create",
  "status": "running",
  "influencerId": "inf_4a8e1bc2-3d4f-46a8-9b0c-1d2e3f4a5b6c"
}
```

The cloned influencer's id (`influencerId` in the response) is server-generated. Persist it on your end and map it back to your entity — you cannot supply your own id.

Clone is async; a render job produces a new portrait using the source influencer's appearance as an anchor, then applies any `overrides` before the new influencer reaches `status: ready`.

## Selecting an influencer for content [#selecting-an-influencer-for-content]

Every content endpoint (`slideshow-builder`, `video-remix`, `slideshow-remix`, `ugc-remix`) accepts an optional `influencerId` on the request body — that wins over any layer-wired influencer. Omit it and the generator falls back to the influencer wired to the project's first Social Content layer (and to the project's default voice + language if no influencer is wired, on `slideshow-builder` only).

If you want a round-robin across multiple influencers on a single project, pass a different `influencerId` per call — the API doesn't rotate for you.

## Lifecycle [#lifecycle]

* `PATCH /v1/influencers/:influencerId` updates `name`, `gender`, `ageRange`, `brandVoice`, or `language`.
* `DELETE /v1/influencers/:influencerId` deletes the influencer from future selection. Body is optional `{ "reason": "..." }`. The response is `{ "influencerId", "status": "deleted", "deletedAt" }`. Deleted influencers still appear on historical content that used them; they just can't be selected for new generations.
