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
Check
Before generating, send the face templates from the input and the prompt. We answer per face.
Generate
Only if the answer is free or cleared. Licensed users pass their license token.
Report
Report each licensed generation. We bill the owner's per-use price and return a signed consent credential for the output.
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
| Decision | Meaning | What to do |
|---|---|---|
| free | No registered face matched. | Generate. |
| cleared | Active license, within the owner's limits. | Generate, then report usage. |
| required | A registered person who licenses this use. | Show the offer. Do not generate. |
| pending | A license request is waiting for the owner. | Do not generate yet. |
| blocked | Protected 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." } }
| Status | Codes |
|---|---|
| 400 | bad_descriptor no_faces too_many_faces bad_use bad_territory bad_units |
| 401 | no_key bad_key wrong_key |
| 404 | no_check no_license |
| 409 | not_cleared check_stale license_inactive |
All endpoints
| Endpoint | Who | What |
|---|---|---|
| POST /v1/likeness/check | Partner | Check faces and prompt before generating |
| POST /v1/usage | Partner | Report a licensed generation, get a credential |
| GET /v1/licenses/{id}/status | Partner | Is this license active |
| POST /v1/webhooks | Partner | Subscribe to license events |
| GET /.well-known/jwks.json | Anyone | Public key for tokens and credentials |
| GET /v1/market | Anyone | Faces open to licensing, with prices and limits |
| POST /v1/licenses | Signed-in brand | Buy or request a license |
| GET /v1/licenses/{id}/token | License holder | A fresh 24-hour token |
| POST /v1/licenses/{id}/renew · /revoke | Holder · owner | Renew a term, or withdraw consent |
| POST /v1/generations | Signed-in brand | Generate 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
- We store face templates, never photos or videos. Owners can delete theirs at any time, which revokes their licenses.
- Protected people are never named in check results or fake reports.
- Prompts you send are shown to the face owner, so they can see how their face is being used. Do not send other personal data in prompts.
- UseMyFace is run by Kapturise FZC in the UAE.