FaceNinja

Developers · REST API

The MetaHuman head API, built for batches.

Send photos of a person, hear back when the head is done, fetch the format you need. The same call makes one head or five hundred. Every head is finished: 4K skin, groom recommendations, a fitted neck and 52 ARKit shapes. A head takes about 4 minutes, so the API is asynchronous by design.

  • REST + JSON
  • Bearer keys
  • Signed webhooks
  • Idempotency keys
  • OpenAPI 3.1
  • llms.txt

Not to be confused with Epic's MetaHuman Python and C++ APIs, which run inside Unreal Engine. FaceNinja is a web API that makes the head you bring into them.

Send. Hear back. Fetch.

  1. Send.

    POST /v1/heads with 1 to 15 photos of one person, as multipart files or ids you uploaded first. Add an Idempotency-Key, and a retry never makes or bills a second head.

  2. Hear back.

    Choose how: a signed webhook to your server, a server-sent event stream, or a ?wait=60 long poll for scripts.

  3. Fetch.

    Ask for glb, fbx, obj, stl, ply or metahuman_zip, with or without ARKit shapes. You get a signed link that needs no key. Store the head id, not the link. What each format holds

A failed head's credits come back automatically, and error.code says why.

A webhook is all your backend needs.

Create the head, store its id, and act when we call you. This is the whole integration, in Python.

Code
# when the user confirms their photos
head = api.post("/v1/heads", files=photos,
                data={"webhook_url": "https://you.example/hooks/faceninja"},
                headers={"Idempotency-Key": str(uuid4())}).json()
save(user, head["id"])

# later, FaceNinja calls you
@app.post("/hooks/faceninja")
def on_head(event = verified(request)):        # check FaceNinja-Signature first
    if event["type"] == "head.completed":
        link = api.post(f"/v1/heads/{event['data']['id']}/files",
                        json={"format": "glb", "arkit": True}).json()
        store_on_your_cdn(link["url"])

Shortened for reading. The reference has the full request, the signature check and every error.

A cast from a folder, safe to run twice.

A batch is many single creates. Give each one an idempotency key you derive from your own data, such as the folder name, and you can rerun the whole script after a crash without making or paying for a head twice. Then let the webhooks tell you which heads are done.

Python
for person in sorted(Path("cast").iterdir()):            # one folder per person
    photos = [("photos", open(p, "rb")) for p in sorted(person.glob("*.jpg"))]
    api.post("/v1/heads", files=photos,
             data={"name": person.name, "webhook_url": HOOK},
             headers={"Idempotency-Key": f"cast-2026-10/{person.name}"})
  • Pace: up to 30 head creations a minute per account. On 429, wait Retry-After seconds and send the same key again.
  • Check first: ?dry_run checks a create and returns a quote without making a head. GET /v1/account shows the balance.
  • Track: GET /v1/heads lists your heads, page by page, with their status.
  • Fail one, not all: a head that fails reports its own error.code, and its credits return. The rest of the batch carries on.

Or let your agent write the integration.

The API reference, the OpenAPI file and llms.txt are written for people and for language models. Give your agent the skill and it can make heads for you directly, or write and test the pipeline script for your stack.

Pipeline prompt
Read https://faceninja.net/llms.txt and https://faceninja.net/skill/SKILL.md. Write a Python script for our pipeline: for each new folder in ./incoming, create one FaceNinja head from its photos with an Idempotency-Key derived from the folder name and a webhook_url I give you. Add a small web handler that checks the FaceNinja-Signature header, and on head.completed downloads the FBX to ./heads/<folder name>; on head.failed it logs error.code. Read the API key from FACENINJA_API_KEY. Don't run anything against my account until I say so.

Built for retries, queues and bad photos.

Idempotent creates

The same Idempotency-Key within 24 hours returns the same head, never a second charge.

Signed webhooks

head.completed and head.failed, with an HMAC signature in FaceNinja-Signature.

Honest queue

While waiting, a head reports its place in line and an estimate.

Errors you can branch on

Stable error.code values (no_face, not_same_person, content_rejected, …) and a hint.

Refunds without tickets

Credits are held at create, charged at completion and released on failure or delete.

Delete on demand

Delete a head and its photos whenever you want. Files expire 30 days after the head finishes.

The numbers to design around.

Limits
Photos per head1 to 15, one person; JPEG, PNG, WebP, HEIC/HEIF or AVIF, up to 25 MiB each
Time per headAbout 4 minutes, plus any queue
Long poll?wait up to 60 s per call
Download linksStart within 60 s; a started download finishes
Rate limits600 requests a minute per account; 30 head creations a minute
RetentionPhotos and files 30 days after the head finishes
Price1,500 credits ($15) per head, every format included

The reference is the source of truth. If a number here differs, the reference wins.

A player's face on day one of the save file.

Let players bring their own face, or build an NPC cast from consenting actors. Every head is the same mesh with a different face, so one rig, one material and one animation set fit them all. The 52 ARKit shapes take lip sync or the player's camera.

Plan for the wait. A head takes about 4 minutes, not milliseconds. Start it early, during onboarding or a tutorial, show a stand-in, and swap the head in when the webhook arrives.

GLB for Unity, Godot and the web; FBX and the MetaHuman ZIP for Unreal. Unreal automation is in early access: ask for it.

Our terms require permission from the person in the photo and forbid photos of children. Build the same rule into your flow.

Synthetic photo of an elderly man in harsh orange lightSynthetic photo of a laughing woman with glassesSynthetic photo of a bearded man with his head turnedSynthetic photo of a woman whose long hair covers her ears
Four synthetic test subjects, one topology.

Already using another photo-to-MetaHuman API?

If your integration already creates a head, waits for it and downloads a file, it keeps its shape here. Paths, field names and the file step differ, and the migration guide maps them call by call.

Developer questions.

01Is there a sandbox?
Add ?dry_run to a create call. It checks the request and returns a quote without making a head or charging you.
02Can I call it from a browser or a mobile app?
No. Keep the key on your server. Signed upload and download links need no key, so a client can upload or download directly.
03Which SDKs are there?
Plain HTTP and an OpenAPI 3.1 file you can generate a client from. The reference has curl, Node and Python examples. The agent skill's CLI is also a single Python file you can read and call from scripts.
04How many heads can I make at once?
Up to 30 head creations a minute per account, and each runs in the queue. For more than 1,000 heads, write to us about invoicing and capacity.
05Is this Epic's MetaHuman API?
No. Epic's MetaHuman APIs script MetaHuman Creator inside Unreal Engine. FaceNinja makes the head from photos, as a web service, and hands you the files and the MetaHuman ZIP to take into Unreal.
06Can it build a head from a set of photos?
Yes, in beta: reconstruction from several photos of one session also returns each photo's camera position and focal length. Write to us if you want to try it with your capture set.

Your first head is one API call away.