API

Run any of your account's 9 generation modes remotely: send a photo, get back the transformed result. One endpoint, one request, JSON response.

Overview

Every API project (created from the API projects page) is configured to run exactly one of the 9 generation modes below - the same modes an event on this platform can run. A single request runs that project's configured mode and returns the resulting image inline as base64 - there is no separate polling step and no file storage involved on either side.

Face swapIdentity transferHeadless head-attachApparel try-onFull randomSelf-promptHeadshotCombinationTeleport

Authentication

Every request is authenticated with an API key tied to one API project. Create a project and get its key from the API projects page in your dashboard (sign-in required). The key is shown in full exactly once, at creation or refresh - store it somewhere safe. It has no expiry; refresh it any time to immediately invalidate the previous one.

Send it as a bearer token:

Authorization: Bearer pb_live_...

Endpoint

POST /api/v1/generate

Request

multipart/form-data:

FieldTypeDescription
imagefile, requiredThe subject/guest photo. JPG, PNG, or WebP. Max 15MB (5MB for a project configured to "headshot" mode - that pipeline's background-removal step has its own hard limit).
referencefile, conditionalA background or garment photo. Required only when your project's configured mode is one of faceswap/identity/headless/apparel/combination/teleport (all of which need a scene or garment to compose onto; for combination and teleport this is the scene) - ignored otherwise. There is no saved asset library on this API - you always supply the reference image inline, every call.
garmentfile, conditionalcombination mode only, required there: the uniform/garment laid out with no person wearing it. Ignored for every other mode.
posefile, conditionalcombination mode only, required there: a full-body photo of someone (or a mannequin) in the pose to copy - only the body pose is taken from it, never the subject, clothing, or background. Ignored for every other mode.
prompttext, optionalOnly used when your project's mode is selfprompt - your own description of the scene you want, up to 500 characters.

Mode is not a request field - it's whatever your project is configured to run, set once on the API projects page.

Response (200)

JSON, with the resulting image returned inline as base64 (not a URL - nothing is stored server-side):

{
  "image": "<base64-encoded image bytes>",
  "contentType": "image/png",
  "width": 1200,
  "height": 1800,
  "mode": "faceswap",
  "creditsUsed": 1,
  "creditBalance": 149
}

Errors

StatusMeaning
400Missing image (or reference/garment/pose, when your mode needs them), or not multipart/form-data
401Missing or invalid Authorization header / API key
402Insufficient credits on the project's account
413An uploaded file exceeds the size limit
422No face was detected in the photo ("headshot" mode only)
429Rate limit exceeded for this API key or IP
502The pipeline failed
504The pipeline didn't complete in time - safe to retry

Every non-200 response body is { "error": "<message>" }.

A note on response time

This endpoint blocks until the result is ready and returns it in one response - there is no separate poll step to implement. For headshot mode this is typically a few seconds. For the other, image-editing modes it can occasionally take noticeably longer (up to several minutes in the worst case) since those run a genuine AI image edit rather than a fast, narrow crop - set a generous client-side timeout if you're calling one of those modes.

Billing

Each successful call debits credits from the same account credit balance your kiosk events use - one shared balance, topped up from your dashboard's billing page. The per-call cost is set per mode by the account's admin and returned as creditsUsed in every successful response, with your remaining balance as creditBalance. A failed call is never billed.

Rate limits

Up to 30 requests per minute per API key. A 429 response means you've exceeded that - wait and retry.

Example

curl

curl -X POST https://oobler.oangle.com/api/v1/generate \
  -H "Authorization: Bearer pb_live_..." \
  -F "[email protected]" \
  -F "[email protected]"

Node.js

const form = new FormData();
form.append("image", fs.readFileSync("photo.jpg"), "photo.jpg");
form.append("reference", fs.readFileSync("scene.jpg"), "scene.jpg");

const res = await fetch("https://oobler.oangle.com/api/v1/generate", {
  method: "POST",
  headers: { Authorization: "Bearer pb_live_..." },
  body: form,
});
const { image, contentType } = await res.json();
fs.writeFileSync("result.png", Buffer.from(image, "base64"));

Python

import base64, requests

with open("photo.jpg", "rb") as image, open("scene.jpg", "rb") as reference:
    res = requests.post(
        "https://oobler.oangle.com/api/v1/generate",
        headers={"Authorization": "Bearer pb_live_..."},
        files={"image": image, "reference": reference},
    )
data = res.json()
with open("result.png", "wb") as out:
    out.write(base64.b64decode(data["image"]))

Machine-readable spec

An OpenAPI 3.0 description of this endpoint is available at /openapi.json.