Die Staging-Engine hinter der Web-App ist jetzt als HTTP-API verfügbar. Sie schicken das Foto eines Raums, nennen einen Raumtyp und einen Möbelstil, und das eingerichtete Bild kommt in derselben Antwort zurück. Es kostet $0.15 pro Bild, es gibt kein Abo, keine Mindestabnahme und keine Monatsrechnung, und die Referenzdokumentation steht unter stagify.ai/developers.html.

Dieser Beitrag ist das, was eine Referenzseite nicht sein kann: warum die API so geschnitten ist, wie sie ist, und die Handvoll Dinge, über die Sie am ersten Nachmittag stolpern werden.

Die ganze API ist ein einziger Endpoint

Es gibt genau einen Aufruf, der Geld kostet.

curl https://stagify.ai/api/v1/renders \
  -H "Authorization: Bearer $STAGIFY_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "image=@living-room.jpg" \
  -F "roomType=Living room" \
  -F "furnitureStyle=modern" \
  -F "labelVirtuallyStaged=true"

Das ist die gesamte Integration. Die Antwort enthält das eingerichtete Bild als Data-URL, dazu einen Status und eine Request-ID. Alles andere in der API ist kostenlos und nur lesend: GET /api/v1/options liefert die zulässigen Werte für jedes Enum, GET /api/v1/me sagt Ihnen, ob Ihr Key funktioniert, GET /api/v1/credits meldet den Kontostand, und GET /api/v1/renders/{id} schlägt einen einzelnen Render nach.

Anfragen laufen über multipart/form-data, denn Sie laden eine Fotografie hoch, und Base64 in einem JSON-Body würde Sie ohne Gegenwert ein Drittel mehr Bytes kosten. Bilder sind JPEG, PNG oder WebP bis 25 MB, und geprüft wird der MIME-Typ, nicht die Dateiendung.

Warum es keine Job-Queue gibt

Der naheliegende Entwurf für eine langsame Bild-API lautet: Anfrage annehmen, eine Job-ID zurückgeben und den Client das Ergebnis pollen lassen. Das haben wir bewusst nicht getan, und der Grund gehört ausgesprochen, denn von außen sieht es nach einer Abkürzung aus, und das ist es nicht.

Diese Anwendung hat überhaupt keine Job-Queue. Eine allein für die API einzuführen hieße, eine Queue einzuführen, deren Jobs in einem einzigen Prozess leben, auf einem Host, der bei jedem Deploy neu startet. Passiert das mitten in einem Render, ist das Guthaben des Kunden bereits verbraucht und es ist kein Socket mehr da, um ihm irgendetwas zu sagen. Dieser Fehlerfall ist strikt schlimmer als eine abgebrochene Verbindung, denn eine abgebrochene Verbindung lässt sich mit demselben Idempotency-Key wiederholen und kostet nichts.

Ein Render hält die Verbindung also offen, bis er fertig ist, und das dauert von wenigen Sekunden bis zu ein paar Minuten. Setzen Sie das Read-Timeout Ihres Clients auf 300 Sekunden. Der Standardwert liegt in den meisten HTTP-Bibliotheken bei 30 oder 60, und ein Client, der nach 30 Sekunden aufgibt, wirkt wie eine ständig scheiternde API, während er still Credits für Renders ausgibt, die er nie abholt.

So gebaut, dass wir später umziehen können, ohne Sie zu brechen: Der Erfolgs-Body trägt bereits status: "succeeded", und GET /api/v1/renders/{id} gibt es bereits. Sollten wir je eine Queue nachrüsten, kommt sie als neuer status-Wert am selben Endpoint, nicht als neue API. Behandeln Sie jeden Status außer succeeded als „jetzt das GET pollen“, und Ihr Client ist schon zukunftssicher.

Dieselbe Überlegung deckelt variations bei 1. Eine Anfrage ist ein Credit ist ein Bild ist eine Rückerstattung, ohne anteilige Fan-out-Rechnerei irgendwo im Geld. Wenn Sie drei Varianten eines Raums wollen, setzen Sie drei parallele Anfragen ab: Damit bekommen Sie mehr Parallelität, als der Fan-out je geliefert hat.

Prepaid-Credits, und warum das ein Sicherheitsmerkmal ist

Sie kaufen Credits im Voraus. Jeder erfolgreiche Render verbraucht einen, und ein fehlgeschlagener Render wird automatisch erstattet, sodass Sie nie für ein Foto zahlen, das Sie nicht bekommen haben. Die Pakete beginnen bei 20 Credits für $3, und der Preis pro Bild sinkt mit der Paketgröße bis auf $0.12 pro Bild im 500-Credit-Paket. Die aktuelle Tabelle steht auf der API-Dokumentationsseite und wird aus denselben Daten erzeugt, gegen die der Zahlungs-Webhook abrechnet, sie kann also nicht von dem abweichen, was Ihnen tatsächlich berechnet wird.

Nutzungsbasierte Abrechnung wäre einfacher zu bauen gewesen. Prepaid ist in einem bestimmten Punkt besser für Sie: Ein gestohlener Key kann Sie höchstens das darauf verbliebene Guthaben kosten. Es gibt keine Rechnung am Monatsende, keine Überschreitung und kein Szenario, in dem ein durchgesickerter Key zu einer vierstelligen Rechnung wird, bevor es jemand bemerkt. Der harte Stopp bei null ist der Zweck und keine Einschränkung, und deshalb trägt auch jede Antwort einen X-Stagify-Credits-Remaining-Header: Sie sehen die Wand näher kommen, ohne danach zu pollen.

Keys sind ausschließlich für den Server-zu-Server-Einsatz gedacht. Die API sendet keine CORS-Header, Browser-JavaScript kann sie also nicht aufrufen, und das ist Absicht und kein Versäumnis, das wir zu beheben planen. Ein aus dem Browser erreichbarer Key ist ein geleakter Key. Wir zeigen einen neuen Key genau einmal, speichern nur seinen Hash und widerrufen ihn auf der Stelle im API-Keys-Dashboard.

Vier Dinge, über die Sie stolpern werden

Jede API hat Verhaltensweisen, die erklärt vollkommen einleuchten und unerklärt rätselhaft sind. Hier sind unsere, klar ausgesprochen statt in einer Parametertabelle versteckt.

  1. roomType unterscheidet Groß- und Kleinschreibung sowie Leerzeichen, und ein falscher Wert wird nicht abgelehnt. Er wird als Freitext in den Prompt geschrieben, also ist Living Room nicht Living room. Sie bekommen einen Render, nur eben nicht den gemeinten, und bezahlt haben Sie ihn. Die zulässige Menge ist Bedroom, Living room, Dining room, Kitchen, Office, Bathroom, Outdoors und Dorm. Holen Sie sie aus GET /api/v1/options, statt sie in Ihr eigenes Dropdown abzutippen.
  2. Ein unbekannter furnitureStyle wird stillschweigend zu standard. Dieselbe Art von Problem, nur leiser: Ein Tippfehler in einem Stilnamen erzeugt keinen Fehler, er gibt Ihnen einfach den Standard-Look auf jedem Bild des Stapels.
  3. removeFurniture akzeptiert true oder on und sonst nichts. Nicht 1, nicht yes. Beides wird als false gelesen, und Sie bekommen ein eingerichtetes Foto, in dem das alte Sofa noch steht. Der zugehörige keepFurniture nimmt Freitext entgegen, der benennt, was stehen bleiben soll, bis zu 500 Zeichen, und wird nur gelesen, wenn removeFurniture tatsächlich gesetzt ist.
  4. Senden Sie bei jeder Anfrage einen Idempotency-Key. Ihn wegzulassen ist erlaubt und bedeutet keinen Replay-Schutz, was der ehrliche Standard ist; wir werden ihn nicht aus Ihrem Foto ableiten, denn dann würden zwei wirklich getrennte Renders desselben Raums kollidieren und der zweite Aufrufer bekäme das Bild des ersten. Wiederholen Sie mit demselben Wert, wird eine abgeschlossene Anfrage mit X-Stagify-Replayed: true aus dem Speicher wiedergegeben, ohne zweite Belastung. Verwenden Sie einen Key mit anderen Parametern erneut, bekommen Sie 422 IDEMPOTENCY_KEY_REUSED — das ist die API, die Ihnen sagt, dass Ihr Key-Generator einen Bug hat.

Darüber hinaus spiegeln die wissenswerten Parameter die Web-App: additionalPrompt für Freitext-Anweisungen und bis zu fünf furnitureImage-Referenzfotos, an denen sich das Modell orientieren soll.

Der Hinweis auf die Bearbeitung lässt sich nicht abschalten

Die meisten MLS-Regeln und die dahinterstehenden NAR-Leitlinien verlangen, dass ein gestaltetes Exposéfoto sagt, dass es gestaltet ist; seit Januar 2026 schreibt Kaliforniens AB 723 das per Gesetz vor. Wir haben die Fassung Bundesstaat für Bundesstaat davon geschrieben, ausführlich.

labelVirtuallyStaged brennt den Hinweis in die Pixel, statt ihn als Metadaten anzuhängen, denn Metadaten werden von so gut wie jedem nachgelagerten Werkzeug entfernt, das ein Bild auf dem Weg zu einem Portal durchläuft. Das Aussehen steuern Sie: stampStyle wählt zwischen dark, light, minimal und banner, stampScale skaliert ihn zwischen 0.7 und 1.6, und stampLang gibt ihn in einer von elf Sprachen aus.

Was Sie nicht steuern, ist der Fehlerfall. Wird der Hinweis angefordert und kann nicht angebracht werden, wird das Bild zurückgehalten statt unbeschriftet ausgeliefert. Der Aufruf antwortet mit 500 DISCLOSURE_STAMP_FAILED und Ihr Credit wird erstattet. Es gibt kein Flag, das das abschaltet, und keine Voreinstellung pro Key, die es stillschweigend deaktiviert. Die Alternative wäre, einem Kunden, der ausdrücklich um die Kennzeichnung gebeten hat, ein unbeschriftetes gestaltetes Foto zu liefern — der eine Bug in diesem System, der jemanden vor eine Aufsichtsbehörde bringen könnte.

Fehler, und die eine Regel dazu

Jeder Fehlschlag antwortet mit einem JSON-Body, der sowohl einen error-String als auch einen code trägt. Verzweigen Sie über den Code, niemals über die Nachricht. Nachrichten werden umgeschrieben; Codes nicht.

Die, denen Sie in der Produktion wirklich begegnen, sind 402 INSUFFICIENT_CREDITS (aufladen; der Body enthält das Restguthaben), 409 CONCURRENCY_LIMIT (zu viele Renders gleichzeitig auf einem Key; der Standard erlaubt drei zur selben Zeit, warten Sie also eine Sekunde und versuchen Sie es erneut), 409 REQUEST_IN_FLIGHT (Sie haben einen Idempotency-Key wiederholt, der noch läuft, warten Sie also, statt nachzulegen), 429 RATE_LIMITED und 422 NO_IMAGE_GENERATED, was bedeutet, dass das Modell nichts zurückgegeben hat, und automatisch erstattet wird. Das Render-Limit liegt derzeit bei 60 pro Key je fünf Minuten; wenn Sie mehr brauchen oder eine Rechnung statt einer Karte, schreiben Sie uns.

Beachten Sie das Muster in all dem: Alles, was nach einer Belastung fehlschlägt, wird erstattet. Diese Invariante ist der Grund, warum die API synchron ist, und der Grund, warum variations bei eins gedeckelt ist, und sie ist das, wofür wir Funktionen aufgeben würden.

Für wen das ist und für wen nicht

Die API gibt es für die Fälle, in denen Staging ein Schritt in der Pipeline von jemand anderem ist und nicht etwas, wofür sich ein Mensch hinsetzt:

Für eine Person, die ein einzelnes Haus staged, ist sie ausdrücklich nicht gedacht. Wenn das auf Sie zutrifft, kann die Web-App mehr als die API, denn Masking Studio und der AI Designer haben kein Gegenstück in der API, und sie ist kostenlos, ohne Wasserzeichen. $0.15 dafür zu zahlen, im Code zu tun, was Sie im Browser umsonst tun können, wäre eine merkwürdige Entscheidung, und das sagen wir lieber, als Ihnen ein Credit-Paket zu verkaufen.

Erste Schritte

Legen Sie auf der API-Keys-Seite einen Key an, kaufen Sie das kleinste Paket und geben Sie einen Credit für ein Foto aus, dessen Ergebnis Sie schon kennen. Lesen Sie dann die Referenz gründlich, bevor Sie die Batch-Schleife schreiben, vor allem die Idempotenz-Tabelle. Zwanzig Credits kosten $3, und das reicht mehr als aus, um herauszufinden, ob das zu Ihrer Pipeline passt.

Quellen und Anmerkungen