Die API ist dieselbe, die auch die Gradiently-App nutzt. Ein Schlüssel sieht also dieselben Daten und durchläuft dieselben Prüfungen wie sein Ersteller in der App, beschränkt auf einen Arbeitsbereich und seine Scopes. Ein Schlüssel, der einen Endpunkt aufruft, den keiner seiner Scopes abdeckt, bekommt 403.
Basis-URL und Authentifizierung
Alle Pfade unten liegen unter https://gradiently.design. Schick deinen Schlüssel bei jeder Anfrage als Bearer-Token mit. Anfragekörper sind JSON mit Content-Type: application/json, außer bei Uploads.
curl https://gradiently.design/api/marks/mine \
-H "Authorization: Bearer gr_live_…"- Ein Schlüssel ist immer an den Arbeitsbereich gebunden, in dem er erstellt wurde. Du musst den Arbeitsbereich nicht angeben; wenn du
X-Workspaceoder?workspace=schickst, muss es der des Schlüssels sein, sonst scheitert die Anfrage mit 403. - Anfragekörper werden streng geprüft: Ein Feld, das der Endpunkt nicht kennt, führt zu 422.
- Antworten sind JSON, sofern nicht anders angegeben (Bilder, Weiterleitungen und der Stream des Designers). Fehlermeldungen an API-Schlüssel sind auf Englisch.
- Ein Schlüssel handelt als sein Ersteller. Designs und Marken, die er erstellt, gehören dem Arbeitsbereich; Marks, die er sichert, hält sein Ersteller.
Arbeitsbereich
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| GET | /api/me | workspaces:read und designs:read | Du, der Arbeitsbereich des Schlüssels und seine Marken. |
| GET | /api/workspaces | workspaces:read | Der Arbeitsbereich des Schlüssels und deine Rolle. |
| GET | /api/workspaces/:id | workspaces:read | Ein Arbeitsbereich. |
| GET | /api/workspaces/:id/members | workspaces:read | Mitglieder mit Name, E-Mail und Rolle. |
| GET | /api/workspaces/:id/audit | workspaces:read | Das Audit-Log des Arbeitsbereichs. |
| POST | /api/workspaces/:id/invites | members:write | Verschickt per E-Mail eine sieben Tage gültige Einladung. |
GET /api/me
{
"viewer": { "id": "…", "name": "Ada Moss", "handle": "ada", "workspaceId": "…" },
"workspaces": [{ "id": "…", "name": "Hearth", "role": "owner" }],
"activeWorkspaceId": "…",
"personalities": [{ "id": "…", "slug": "hearth", "name": "Hearth", "markId": "…" }]
}POST /api/workspaces/:id/invites
{ "email": "sam@example.com", "role": "editor" }
{ "id": "…", "expiresInDays": 7 }role ist admin, editor oder viewer. Die Person muss dieselbe E-Mail-Adresse bestätigen, bevor sie annimmt.Marken
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| GET | /api/personalities | designs:read | Die Marken des Arbeitsbereichs, als { items }. |
| POST | /api/personalities | personalities:write | Erstellt eine Marke. |
| PATCH | /api/personalities/:id | personalities:write | Benennt eine Marke um, setzt ihren Mark, ihr Profil oder ihren Stil. |
| DELETE | /api/personalities/:id | personalities:write | Löscht eine Marke und ihre Designs. Ein Arbeitsbereich behält mindestens eine. |
| GET | /api/personalities/:id/designs | designs:read | Die Designs einer Marke, die neuesten zuerst. |
| GET | /api/personalities/:id/brand | designs:read | Die Schriften, Logos und gespeicherten Farben einer Marke. Ein Schlüssel kann sie lesen, aber nie ändern. |
POST /api/personalities
{ "name": "Hearth Bakery", "markId": "…" }
PATCH /api/personalities/:id
{ "profile": { "about": "A neighbourhood bakery", "voice": "warm, plain" } }
{ "id": "…", "slug": "hearth-bakery", "name": "Hearth Bakery", "markId": "…", "profile": { … } }markId ist beim Erstellen optional. Ein Profil kann außerdem audience, uses, keywords, dos, donts, website, handle und fonts enthalten.Die Designliste nimmt ?q= für die Suche in Titeln und ?mark= als Filter nach Mark. Jeder Eintrag hat id, personalityId, markId, title, form, thumb, shared und updatedAt, ohne das Dokument.
Designs
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| POST | /api/agent/compose | designs:write | Setzt Text, remixt eine Vorlage oder wendet Änderungen an, und speichert. |
| POST | /api/designs | designs:write | Erstellt ein Design aus einem Dokument. |
| GET | /api/designs/:id | designs:read | Ein Design mit seinem Dokument. |
| PATCH | /api/designs/:id | designs:write | Ändert Titel, Dokument, Mark oder Freigabe. |
| DELETE | /api/designs/:id | designs:write | Löscht ein Design. |
| POST | /api/designs/:id/duplicate | designs:write | Speichert eine Kopie daneben. |
| GET | /api/designs/:id/thumb | designs:read | Sein Vorschaubild. |
| POST | /api/designs/:id/render | designs:read | Rendert es als PNG oder PDF. |
Am einfachsten erstellst du ein Design per Code mit POST /api/agent/compose: Du beschreibst den Inhalt, und die Layout-Engine platziert ihn mit dem Mark der Marke. Derselbe Endpunkt remixt eine Vorlage (template mit text, photos, icons, hide) oder bearbeitet mit designId und ops ein gespeichertes Design.
POST /api/agent/compose
{
"personalityId": "…",
"composition": {
"size": "ig-post",
"layout": "statement",
"blocks": [
{ "role": "headline", "text": "Fresh bread from 7am" },
{ "role": "cta", "text": "Visit us" }
]
}
}
{ "id": "…", "url": "/studio/…", "issues": [ … ], "elements": [ … ] }issues listet, was die Prüfung gefunden hat (Ränder, Überschneidungen, Hierarchie, Kontrast).POST /api/designs
{
"personalityId": "…",
"form": "blank",
"title": "Launch post",
"doc": { "ratio": "custom", "width": 1080, "height": 1350, "shift": [0.5, 0.5, 0.5, 0.5], "elements": [] }
}
{ "id": "…", "personalityId": "…", "markId": null, "title": "Launch post", "form": "blank", "doc": { … }, "updatedAt": "…", "thumb": null, "shared": false }markId ist optional; ohne diese Angabe trägt das Design den Mark der Marke. Lies ein Design mit GET /api/designs/:id, um ein vollständiges Dokument zu sehen.PATCH /api/designs/:id nimmt beliebige von title, doc, markId und shared. Wenn du shared auf true setzt, wird ein Ansichtslink unter /d/:id veröffentlicht. Schick baseUpdatedAt, also das updatedAt, das du zuletzt gelesen hast, damit das Speichern mit 409 abgelehnt wird, falls jemand das Design inzwischen geändert hat.
POST /api/designs/:id/render
{ "width": 1080, "height": 1350, "format": "png", "page": 0 }
{ "id": "…", "data": "iVBORw0KGgo…", "encoding": "base64", "mimeType": "image/png", "width": 1080, "height": 1350, "pages": 1 }page zählt ab 0; ein PDF ohne page enthält jede Seite, jeweils in ihrer Größe aus dem Studio, zu der die Anfrage passen muss. Rechne mit bis zu drei Minuten.Zum Rendern braucht es für den Mark des Designs dieselbe Exportlizenz wie im Studio; ohne sie lautet die Antwort 402. Beim Rendern wird das Design nie veröffentlicht und keine Datei gespeichert.
Uploads
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| POST | /api/uploads | designs:write | Lädt ein Bild für Designs hoch. |
| GET | /api/uploads | designs:read | Die Uploads des Arbeitsbereichs, die neuesten zuerst. |
| GET | /api/uploads/:id | designs:read | Leitet zum Bild weiter. ?w= fragt eine Breite an. |
| DELETE | /api/uploads/:id | designs:write | Löscht einen deiner Uploads. |
curl https://gradiently.design/api/uploads \
-H "Authorization: Bearer $GRADIENTLY_API_KEY" \
-F "file=@shopfront.jpg;type=image/jpeg"
# { "id": "…", "url": "/api/uploads/…" }file: PNG, JPEG, WebP, GIF oder AVIF, höchstens 8 MB, mit einem Typ, der zum Inhalt passt. Nutze die zurückgegebene url als src eines Bildes oder als Foto in einer Vorlage.Marks
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| GET | /api/marks | marks:read | Durchsucht den Markt. |
| GET | /api/marks/:code | marks:read | Ein Mark mit seinem Rezept, per Code oder ID. |
| GET | /api/marks/mine | marks:read | Marks, die für den Arbeitsbereich gehalten werden, und deine Entwürfe darin. |
| POST | /api/agent/mark | marks:read | Baut oder bearbeitet ein Rezept und prüft es. Speichert nichts. |
| POST | /api/marks | brand:generate | Speichert ein Rezept als Mark-Entwurf. |
| PATCH | /api/marks/:id | brand:generate | Ändert einen Entwurf, den du gemacht hast. |
| POST | /api/marks/:code/claim | marks:claim | Sichert einen verfügbaren Mark. |
| POST | /api/marks/:code/buy | marks:claim | Sichert einen Mark, den ein anderer Inhaber anbietet. |
GET /api/marks nimmt q (Name oder Code), tone (dark oder light), material, status (listed, house oder sale) und cursor. Die Antwort ist { "items": [ … ], "nextCursor": "…" } mit 24 Marks pro Seite. Ein Mark hat id, code, name, recipe, status, creator, holder und createdAt.
POST /api/marks
{ "name": "Night Harbour", "recipe": { … }, "personalityId": "…" }
{ "id": "…", "code": "GR·K7Q2·MX", "name": "Night Harbour", "status": "draft", "recipe": { … } }recipe bekommst du von POST /api/agent/mark mit einer spec. Mit personalityId wird der Entwurf in dieser Marke gespeichert. Ohne sie speichert ein Schlüssel den Entwurf in der ersten Marke seines Arbeitsbereichs und scheitert mit 404, wenn es keine gibt. Eine Person kann bis zu 50 Entwürfe haben.Gesichert wird immer für den Ersteller des Schlüssels, nie für den Arbeitsbereich. Kostenloses Sichern und Sichern, das durch ein Guthaben zum Sichern gedeckt ist, wird sofort abgeschlossen. Braucht das Sichern eine Zahlung, antwortet es mit 402 und checkout: true, und buy antwortet mit 409 und checkout: true; schließ diese Fälle in Gradiently ab, denn ein Schlüssel kann nicht bezahlen. buy nimmt { "priceCents": … }, den angebotenen Preis, den du gesehen hast, und scheitert mit 409, wenn er sich geändert hat.
Versionen von Marks
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| GET | /api/marks/:code/versions | marks:read | Versionen, die neuesten zuerst, als { items, next, canEdit }. |
| GET | /api/marks/:code/versions/:vid | marks:read | Eine Version. |
| POST | /api/marks/:code/versions | brand:generate | Speichert eine Version: { label, recipe }, beides optional. |
| PATCH | /api/marks/:code/versions/:vid | brand:generate | Benennt um oder vergibt einen Stern: { label, starred }. |
| DELETE | /api/marks/:code/versions/:vid | brand:generate | Löscht eine Version. |
| POST | /api/marks/:code/versions/:vid/restore | brand:generate | Macht die Version wieder zum Entwurf. |
Markengenerierung
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| POST | /api/brand/generate | brand:generate | Gibt Markenvorschläge zurück. Schreibt nichts. |
| POST | /api/brand/adopt | brand:generate | Erstellt aus einem Vorschlag einen Mark-Entwurf, eine Marke und drei Startdesigns. |
POST /api/brand/generate
{ "name": "Hearth", "description": "A neighbourhood bakery", "tone": ["calm", "warm"], "count": 4 }
[{ "key": "…", "name": "Hearth One", "recipe": { … }, "personality": { "name": "Hearth", "handle": "…" }, "starters": [ … ], "why": "…" }]
POST /api/brand/adopt
{ "input": { "name": "Hearth", "description": "A neighbourhood bakery", "tone": ["calm", "warm"], "count": 4 }, "key": "…" }
{ "mark": { … }, "personality": { … }, "designs": [ … ] }Der Designer
| Methode | Pfad | Scope | Was er tut |
|---|---|---|---|
| POST | /api/agent | designs:write | Ein Durchgang des Designers, gestreamt als zeilengetrenntes JSON. |
| POST | /api/batches | designs:write | Startet eine Reihe von Designs aus einem Briefing. |
| GET | /api/batches | designs:read | Deine Reihen, laufende und kürzliche. |
| GET | /api/batches/:id | designs:read | Der Fortschritt einer Reihe. |
| DELETE | /api/batches/:id | designs:write | Stoppt eine Reihe. Fertige Designs bleiben. |
| GET | /api/agent/runs?designId= | designs:read | Durchgänge des Designers, die für ein Design noch laufen. |
| DELETE | /api/agent/runs/:id | designs:write | Stoppt einen laufenden Durchgang. |
POST /api/batches
{
"personalityId": "…",
"see": false,
"plan": {
"brief": "Autumn menu launch, Saturday 4 October",
"items": [
{ "size": "ig-post", "brief": "The announcement" },
{ "size": "ig-story", "brief": "Three new loaves, one line each" }
]
}
}
{ "id": "…", "state": "running", "items": [{ "index": 0, "title": "…", "state": "…" }] }GET /api/batches/:id regelmäßig ab; jeder Eintrag bekommt eine designId und eine url, sobald er gespeichert ist. state endet als done, stopped oder failed.Der Designer verbraucht die KI-Credits des Arbeitsbereichs. Liegt das Guthaben unter dem, was ein Durchgang braucht, antworten /api/agent und /api/batches mit 402 und code: "credits". Pro Person laufen höchstens zwei Reihen gleichzeitig. Das Werkzeug design unter MCP und KI-Assistenten liest den Stream des Designers und speichert das Ergebnis für dich, was einfacher ist, als den Stream selbst zu verarbeiten.
Fehler
Ein Fehler antwortet mit einem Statuscode und einem JSON-Körper mit einer lesbaren Meldung in error. Manche fügen Felder hinzu, die unten genannt sind. Die einzige Ausnahme ist /api/mcp: Ein Körper, der kein gültiges JSON ist, antwortet mit 400 und stattdessen einem JSON-RPC-Fehlerobjekt, { "jsonrpc": "2.0", "id": null, "error": { "code": -32700, "message": "Parse error" } }.
{ "error": "API key lacks required scope for this endpoint." }| Status | Wann |
|---|---|
| 401 | Kein Schlüssel, ein fehlerhafter Schlüssel oder ein Schlüssel, der widerrufen ist oder dessen Ersteller kein Inhaber oder Admin mehr ist. |
| 402 | Eine Zahlung oder Credits sind nötig: ein Sichern mit Preis (checkout: true), keine Exportlizenz oder zu wenige KI-Credits (code: "credits"). |
| 403 | Dem Schlüssel fehlt ein Scope, er gehört zu einem anderen Arbeitsbereich, oder die Rolle seines Erstellers erlaubt die Aktion nicht. |
| 404 | Der Eintrag existiert nicht, oder der Schlüssel kann ihn nicht sehen. |
| 409 | Ein Konflikt: Der Eintrag hat sich geändert, seit du ihn gelesen hast, ein Name ist vergeben, oder die Aktion braucht einen Checkout. |
| 422 | Die Anfrage hat die Validierung nicht bestanden. Die Meldung sagt, welches Feld und warum. |
| 429 | Zu viele Anfragen. Warte die Sekunden aus Retry-After ab und versuch es noch mal. |
| 503 | Ausgelastet oder vorübergehend nicht verfügbar, zum Beispiel der Designer oder Exporte. Beachte Retry-After. |
| 504 | Ein Rendering hat zu lange gedauert. Versuch eine kleinere Größe oder eine einzelne Seite. |
Ratenlimits
Limits zählen über ein gleitendes Fenster von einer Minute, sofern nicht anders angegeben. Wer darüber liegt, bekommt 429 mit einem Header Retry-After in Sekunden und einem Feld retryAfter im Körper. Werde langsamer und versuch es nach dieser Zeit erneut; wiederhole die Anfrage nicht sofort.
| Limit | Kontingent |
|---|---|
| Jede Anfrage mit einem Schlüssel | 120 pro Minute und Schlüssel |
| Schreibzugriffe (POST, PATCH, DELETE) | 90 pro Minute und Konto, gemeinsam mit der App |
| Renderings | 10 pro Minute und Konto |
| Neue Designs und Duplikate | 60 pro Minute und Konto |
| Uploads | 60 pro Minute und Konto |
| Sichern | 20 alle zehn Minuten und 100 pro Tag und Konto |
| Einladungen | 30 pro Stunde und Konto |
Exporte und der Designer haben außerdem eine gemeinsame Kapazität. Ist sie ausgeschöpft, lautet die Antwort 503 oder 429 mit Retry-After, auch wenn du unter deinen eigenen Limits liegst. Über MCP zählt ein Werkzeugaufruf einmal für die MCP-Anfrage und einmal für jede API-Anfrage, die das Werkzeug stellt.
Paginierung
Listen liefern eine Seite nach der anderen. Die nächste Seite fragst du mit ?cursor= an.
- Suche im Markt (
/api/marks): 24 pro Seite. Gib dennextCursoraus der Antwort mit; auf der letzten Seite ist er null. - Versionen von Marks: Gib den Wert
nextaus der Antwort mit; auf der letzten Seite ist er null. - Designs einer Marke: 100 pro Seite, die neuesten zuerst. Gib die
iddes letzten Designs mit, das du bekommen hast. - Uploads: 60 pro Seite, die neuesten zuerst. Gib die
iddes letzten Uploads mit. - Marken, Arbeitsbereiche, Mitglieder und das Audit-Log: 100 pro Seite. Gib die
iddes letzten Eintrags mit (userIdbei Mitgliedern). Marken werden über/api/personalitiesals{ items }aufgelistet.
Schlüssel, Scopes und Rotation findest du unter API-Schlüssel und Scopes. Fehlt ein Endpunkt, den du brauchst, sag uns Bescheid.

