Layers

POST /v1/projects/:projectId/influencers

Kick off an influencer-create job. Returns 202 with a job envelope.

View as Markdown
POST/v1/projects/:projectId/influencers
Phase 1stableidempotent
Auth
Bearer
Scope
influencers:write

Starts an influencer_create job. We insert the identity row synchronously (status: "pending") and kick off a background workflow for reference-image rendering. The response is a job envelope — poll /v1/jobs/:jobId for terminal state, then read the influencer at /v1/influencers/:influencerId.

Idempotency

Pass influencerId in the body to make creation idempotent on your side. If the id already exists in this project, we return 409 CONFLICT. Also set an Idempotency-Key header — we cache the response for 24 hours.

Path parameters

  • projectId
    string (uuid)required
    The project this influencer belongs to.

Body

Body
  • name
    stringrequired
    Display name, 1-128 chars.
  • influencerId
    string (uuid)optional
    Your id for idempotency. Omit to let us generate one.
  • gender
    stringoptional
    Drives voice and rendering.
    One of: male, female, nonbinary, unspecified
  • ageRange
    string (max 16)optional
    Free-form age band, e.g. `25-34`.
  • ethnicity
    string (max 128)optional
    Free-form ethnicity descriptor.
  • bodyType
    string (max 128)optional
    Free-form body descriptor.
  • hairColor
    string (max 64)optional
    Free-form hair color.
  • hairStyle
    string (max 128)optional
    Free-form hair style.
  • style
    string (max 256)optional
    Fashion / visual style.
  • vibe
    string (max 256)optional
    Overall vibe descriptor.
  • voiceDescription
    string (max 1024)optional
    How they sound on camera.
  • personality
    objectoptional
    Optional nested object: `{ traits?: string[], tone?, humor?, formality?, values?: string[], interests?: string[], speakingStyle?, catchphrases?: string[] }`.
  • referenceImages
    objectoptional
    Optional `{ assetIds: string[] }` — 1 to 20 media asset ids to seed the identity.

Request

terminal
curl -X POST https://api.layers.com/v1/projects/{projectId}/influencers \
  -H "X-Api-Key: $LAYERS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8d2f1a3e-0b4c-4a11-9f7e-33c0a2c1bd55" \
  -d '{
    "name": "Ava Chen",
    "gender": "female",
    "ageRange": "25-34",
    "style": "minimalist streetwear",
    "vibe": "warm and curious",
    "personality": {
      "traits": ["curious", "warm", "direct"],
      "tone": "conversational",
      "humor": "dry"
    }
  }'
create-influencer.ts
const res = await fetch(
  `https://api.layers.com/v1/projects/${projectId}/influencers`,
  {
    method: 'POST',
    headers: {
      'X-Api-Key': process.env.LAYERS_API_KEY!,
      'Content-Type': 'application/json',
      'Idempotency-Key': crypto.randomUUID(),
    },
    body: JSON.stringify({
      name: 'Ava Chen',
      gender: 'female',
      ageRange: '25-34',
      personality: { traits: ['curious', 'warm', 'direct'] },
    }),
  },
);
const { jobId, influencerId } = await res.json();
create_influencer.py
import os, uuid, httpx

r = httpx.post(
    f"https://api.layers.com/v1/projects/{project_id}/influencers",
    headers={
        "X-Api-Key": os.environ["LAYERS_API_KEY"],
        "Content-Type": "application/json",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "name": "Ava Chen",
        "gender": "female",
        "ageRange": "25-34",
        "personality": {"traits": ["curious", "warm", "direct"]},
    },
)
job = r.json()

Responses

202Job accepted. The influencer row exists (status: pending); poll the job for completion.
{
  "jobId": "job_01HXZ9G7KMV2QX8Y1S5RJW3B7T",
  "kind": "influencer_create",
  "status": "running",
  "influencerId": "inf_01HXZ9...",
  "locationUrl": "/v1/jobs/job_01HXZ9G7KMV2QX8Y1S5RJW3B7T"
}
409influencerId already exists in this project.
{
  "error": {
    "code": "CONFLICT",
    "message": "Influencer with this id already exists.",
    "requestId": "req_..."
  }
}
422Validation failed.
{
  "error": {
    "code": "VALIDATION",
    "message": "Invalid body.",
    "requestId": "req_...",
    "details": { "fieldErrors": { "name": ["Required"] } }
  }
}

Notes

Creation is async. The row is created as status: "pending" synchronously, then the background job transitions it through training to ready. The referenceImages array is populated as the job generates them.

  • Safe to reference immediately. You can use the influencerId in POST /v1/projects/:projectId/content the moment this call returns — the content workflow blocks until the influencer is ready.
  • Status values. draft, pending, training, ready, failed.
  • Reference image seeds. Pass referenceImages.assetIds (media asset ids from /v1/projects/:projectId/media) to seed the identity from photos instead of text.

Errors

CodeWhen
VALIDATIONMissing/invalid field, enum out of range, or bad JSON.
CONFLICTinfluencerId already exists in this project.
NOT_FOUNDProject id not in this org.
FORBIDDEN_SCOPEKey lacks influencers:write.

See also

On this page