UseMyFaceDevelopers

One call before you generate a real person.

The UseMyFace check tells your image or video tool, in milliseconds, whether a face is free to use, licensed, needs a license, or is protected. People set the rules for their own face. You get legal cover and a catalogue of real faces you can license.

How it works

01

Check

Before generating, send the face templates from the input and the prompt. We answer per face.

02

Generate

Only if the answer is free or cleared. Licensed users pass their license token.

03

Report

Report each licensed generation. We bill the owner's per-use price and return a signed consent credential for the output.

Images never leave your servers. You compute a 128-number face template locally and send only that. Protected people are never identified to you: you learn that a face is blocked, not whose it is.

Quickstart

import { UseMyFace, LikenessBlocked } from './usemyface.js';
const umf = new UseMyFace({ apiKey: process.env.UMF_KEY });

try {
  const { output, credentials } = await umf.guard(
    { descriptors, prompt, use: 'ad', territory: 'GCC', licenseToken },  // licenseToken: from your user, if they hold one
    () => model.generate(prompt),                                       // runs only when allowed
    { units: 8, unit: 'second' }
  );
  // attach credentials[i].c2pa_assertion to the output's C2PA manifest
} catch (e) {
  if (e instanceof LikenessBlocked) showUser(e.result.faces);         // reasons, and an offer to license
}

API keys

Send your key as a bearer token. Test keys start with umf_test_, live keys with umf_live_. Keep keys on your server.

Authorization: Bearer umf_live_…

Base URL: https://usemyface.pages.dev. Partner access is free during the pilot. Kapturise issues keys to partners directly.

Likeness check

POST/v1/likeness/check

{
  "descriptors": [[0.0123, -0.0841, …128 numbers], …],  // one per face in the input, up to 10
  "prompt": "Smiling in a running jacket at sunrise",
  "use": "ad",               // personal | social | ad | film | training
  "territory": "GCC",        // where the output will run
  "license_token": "eyJ…",   // optional, from a licensed user
  "end_user": "Northwind Apparel"  // optional, shown to the face owner
}

Response:

{
  "decision": "required",     // the strictest across all faces
  "generate": false,
  "faces": [{
    "index": 0, "decision": "required", "check_id": "chk_…", "match_pct": 94,
    "face_id": "f_…", "name": "Layla Haddad",
    "reasons": ["A license is needed before generating this person."],
    "offer": { "price_cents": 90000, "per_use_cents": 545, "term_days": 30, "approval": false, "url": "https://usemyface.pages.dev/app/#market" }
  }]
}

Limits are checked against the prompt in English and Arabic: nudity, sexual content, swimwear, violence, alcohol and gambling, politics, religion, medical or financial claims, and brands the owner blocked. A license never overrides them.

Decisions

DecisionMeaningWhat to do
freeNo registered face matched.Generate.
clearedActive license, within the owner's limits.Generate, then report usage.
requiredA registered person who licenses this use.Show the offer. Do not generate.
pendingA license request is waiting for the owner.Do not generate yet.
blockedProtected face, use or market not allowed, or the prompt breaks a limit.Do not generate. Show the reasons.

License tokens

When a user buys a license on UseMyFace, they get a license token to paste into your tool, or your tool fetches it on their behalf. Tokens are Ed25519-signed JWTs that last 24 hours at most. Verify them offline with our public key, and rely on the check for revocation: a revoked license stops clearing at once, even with an unexpired token.

GET /.well-known/jwks.json

{ "iss": "usemyface", "typ": "license", "sub": "l_…", "face": "f_…", "use": "ad",
  "terr": ["GCC"], "lim": ["nudity", "sexual"], "per_use_cents": 545, "iat": …, "exp": … }

GET/v1/licenses/{id}/status → { "status": "active" | "revoked" | "expired" | …, "active": true }

Usage and consent credentials

POST/v1/usage

{ "check_id": "chk_…", "units": 8, "unit": "second", "output_sha256": "9f2c…" }

→ { "usage_id": "use_…", "amount_cents": 4360, "credential": "eyJ…",
    "c2pa_assertion": { "label": "com.usemyface.consent", "data": { … } } }

Report once per cleared face, within 6 hours of the check. Repeating the same check_id is safe and returns the first result. Add the assertion to the output's C2PA manifest so anyone can confirm the person consented.

Webhooks

POST/v1/webhooks { "url": "https://…", "events": ["*"] }

Events: license.activated, license.renewed, license.revoked, license.expired. On license.revoked, stop any queued jobs that use that license. Each delivery has a UMF-Signature: t=…,v1=… header, an HMAC-SHA256 of t + "." + body with your webhook secret. Failed deliveries retry for about a day.

import { verifyWebhook } from './usemyface.js';
if (!(await verifyWebhook(rawBody, req.headers['umf-signature'], process.env.UMF_WEBHOOK_SECRET))) return res.status(401).end();

Errors

{ "error": { "code": "bad_descriptor", "message": "Each descriptor must be an array of 128 numbers." } }
StatusCodes
400bad_descriptor no_faces too_many_faces bad_use bad_territory bad_units
401no_key bad_key wrong_key
404no_check no_license
409not_cleared check_stale license_inactive

All endpoints

EndpointWhoWhat
POST /v1/likeness/checkPartnerCheck faces and prompt before generating
POST /v1/usagePartnerReport a licensed generation, get a credential
GET /v1/licenses/{id}/statusPartnerIs this license active
POST /v1/webhooksPartnerSubscribe to license events
GET /.well-known/jwks.jsonAnyonePublic key for tokens and credentials
GET /v1/marketAnyoneFaces open to licensing, with prices and limits
POST /v1/licensesSigned-in brandBuy or request a license
GET /v1/licenses/{id}/tokenLicense holderA fresh 24-hour token
POST /v1/licenses/{id}/renew · /revokeHolder · ownerRenew a term, or withdraw consent
POST /v1/generationsSigned-in brandGenerate a licensed face through UseMyFace

The full contract is in openapi.yaml.

JavaScript SDK

One file, no dependencies, for Node 18+, Deno, Bun, Workers and browsers. Download usemyface.js.

umf.check({ descriptors, prompt, use, territory, licenseToken })
umf.reportUsage({ checkId, units, unit, outputSha256 })
umf.guard(params, generate, { units, unit })   // check → generate → report
umf.verifyToken(token)                         // offline signature check
umf.licenseStatus(id)
verifyWebhook(rawBody, signature, secret)

Face templates

Templates are the 128-number descriptors produced by @vladmandic/face-api (tiny face detector, 68-point landmarks, face recognition net). Run it in the browser or in Node with TensorFlow. Faces match at a distance of 0.5 or less.

import { templatesFromFaceApi } from './usemyface.js';
const descriptors = await templatesFromFaceApi(faceapi, image);  // one per face

Privacy