Dokumentationvom Schlüssel zum ersten Clip
Alles für eine erste Generierung: ein Schlüssel, eine Anfrage, der Auftrag und der Webhook.
Zugang zur Entwickler-API gibt es auf Antrag.
Überblick
REST über HTTPS, JSON rein und raus. Jede Generierung läuft asynchron.
- Basis-URL
https://api.pershot.app/v1- Authentifizierung
- Authorization: Bearer, gefolgt von deinem Schlüssel. Schlüssel beginnen mit sk_test_ oder sk_live_ und werden nur einmal angezeigt; wir speichern nur einen Hash.
- Schlüsselberechtigungen
- Jeder Schlüssel hat Scopes und, wenn du im Studio eine festlegst, eine Positivliste mit Modellen und Tools. Ein Schlüssel mit Positivliste kann nur nutzen, was darauf steht, Tools eingeschlossen: Bild-Upscaling, Hintergrundentfernung, Verbessern, Lippensynchronisation, Outpainting und den Bildeditor. Alles andere antwortet mit 403 forbidden_model. 1080p oder 4K mit Verbessern braucht sowohl das Videomodell als auch Verbessern.
- Fehlerformat
{ "error": { "code", "message", "param", "request_id" } }- IDs
- Mit Präfix nach Typ: job_, qt_, key_, up_.
- OpenAPI
- /api/v1/openapi.json
- Für KI-Agenten
- Klartext für KI-Agenten: Eingaben, zulässige Werte, jeder Preis und ein Anfragebeispiel
seedance-2.0-fastseedance-2.0-miniqwen-image-2512-lightningqwen-image-2512qwen-image-edit-2511-lightningqwen-image-edit-2511
Echte Generierungen sind noch nicht verfügbar. Hinterlass deine E-Mail-Adresse auf einer Modellseite, dann schreiben wir dir einmal, sobald sie verfügbar sind.
Schnellstart
Vier Schritte, jeweils mit der Antwort, die du sehen solltest.
- 01
Schlüssel bekommen
Zugang zur Entwickler-API gibt es auf Antrag: Beantrage ihn im Studio unter API-Schlüssel. Sobald er freigeschaltet ist, leg dort einen Schlüssel an und kopiere ihn sofort: Der vollständige Schlüssel wird nur einmal angezeigt.
export API_KEY="sk_test_…" - 02
Anfrage senden
Sende die Einstellung per POST mit einem Idempotency-Key und einer max_credits-Obergrenze. Du bekommst sofort 202 und einen Auftrag in der Warteschlange, und die Credits werden reserviert.
curl https://api.pershot.app/v1/videos/generations \ -H "Authorization: Bearer $API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.0-fast", "prompt": "Perfume mist in hard side light. Slow push-in, black background, grain.", "duration": 5, "resolution": "720p", "aspect_ratio": "16:9", "generate_audio": true, "max_credits": 34 }'{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "queued", "money_status": "reserved", "queue_position": 2, "requested_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": null } - 03
Auftrag prüfen
Frag den Auftrag per GET ab, bis sein Status succeeded ist. Die Ausgabe-URL ist signiert und läuft ab; lade herunter, was du behalten willst.
curl https://api.pershot.app/v1/jobs/job_01J9ZK4T8W \ -H "Authorization: Bearer $API_KEY"{ "id": "job_01J9ZK4T8W", "object": "job", "kind": "video", "status": "succeeded", "money_status": "settled", "requested_model": "seedance-2.0-fast", "resolved_model": "seedance-2.0-fast", "credits_quoted": 34, "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ], "error": null } - 04
Webhook empfangen
Übergib webhook_url, dann senden wir jede Statusänderung per POST dorthin, signiert mit einem Zeitstempel. Antworte mit 2xx; fehlgeschlagene Zustellungen werden in wachsenden Abständen wiederholt.
{ "id": "evt_01J9ZKB1QX", "type": "job.succeeded", "created_at": "2026-09-29T14:02:31Z", "data": { "job": { "id": "job_01J9ZK4T8W", "object": "job", "status": "succeeded", "money_status": "settled", "credits_charged": 34, "outputs": [ { "kind": "video", "url": "https://…/job_01J9ZK4T8W.mp4?sig=…", "width": 1280, "height": 720, "duration_s": 5 } ] } } }
Endpunkte
Alle Pfade sind relativ zur Basis-URL.
| Methode | Pfad | Funktion |
|---|---|---|
| GET | /v1/models | Modelle, Fähigkeiten und Status, die deinem Konto zur Verfügung stehen |
| GET | /v1/pricing | Öffentliche Preise; angemeldet die Preise deines Kontos |
| POST | /v1/quotes | Plan, Positionen, maximale Abbuchung und Ablauf (10 Minuten) |
| POST | /v1/videos/generations | Video generieren; 202 und ein Auftrag |
| POST | /v1/images/generations | Bild generieren oder bearbeiten; 202 und ein Auftrag |
| GET | /v1/jobs/{id} | Status, Ausgaben als signierte Links, tatsächliche Kosten |
| GET | /v1/jobs | Deine Aufträge, neueste zuerst |
| POST | /v1/jobs/{id}/cancel | Abbruch anfordern; die reservierten Credits werden zurückgebucht, außer das Modell hat den Auftrag schon angenommen |
| GET | /v1/balance | Verfügbare und reservierte Credits, nach Guthabenart |
| GET | /v1/usage | Nutzung nach Tag oder Modell, als JSON oder CSV |
| POST | /v1/uploads | JPEG, PNG oder WebP bis 10 MB hochladen |
Preisangebote und Obergrenzen
Jede Generierung braucht entweder eine quote_id oder eine max_credits-Obergrenze, nie beides. Mit quote_id läuft der Auftrag zu diesem Preisangebot; mit max_credits läuft er nur, wenn der Preis die Obergrenze nicht überschreitet.
model: "auto" braucht immer max_credits. Ein Preisangebot gilt 10 Minuten; danach bekommst du quote_expired.
Idempotenz
Sende bei jeder Generierungsanfrage einen Idempotency-Key-Header (1 bis 255 sichtbare ASCII-Zeichen).
Derselbe Schlüssel innerhalb von 24 Stunden liefert denselben Auftrag mit HTTP 200 statt 202, sodass eine Wiederholung nach einem Timeout nie einen zweiten Auftrag anlegt oder berechnet.
Webhooks
Übergib webhook_url bei einer Generierung (oder bei einem Stapel), um die Statusänderungen zu erhalten. Jedes Ereignis ist ein POST, dessen JSON-Body id, type, created_at und data enthält: data.job für Auftragsereignisse, data.batch für batch.completed.
Ereignisse
job.queuedjob.processingjob.succeededjob.failedjob.cancelledbatch.completed
- Jede Zustellung hat eine Ereignis-ID, einen Zeitstempel und eine Signatur. Prüfe sie, bevor du dem Body vertraust.
- Eine Zustellung gilt als erfolgreich, wenn dein Endpunkt innerhalb von 10 Sekunden mit 2xx antwortet. Sonst wird sie nach 1 min, 5 min, 30 min, 2 h und 6 h wiederholt und dann als fehlgeschlagen markiert; der Support kann sie erneut senden. Weiterleitungen werden nicht verfolgt.
- Webhook-URLs müssen https verwenden. Hosts mit privaten, Loopback- oder reservierten Adressen werden abgelehnt, sowohl beim Einreichen als auch beim Verbinden.
Header
X-Signaturet=<unix>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>X-Event-Id- Die Ereignis-ID, auch im Body. Wiederholungen und erneute Zustellungen behalten sie bei, also speichere sie und überspringe IDs, die du schon verarbeitet hast.
- Signaturgeheimnis
- Ein whsec_…-Geheimnis pro Konto, im Studio unter API-Schlüssel. Der HMAC-Schlüssel ist das ganze Geheimnis, inklusive Präfix.
- Rotation
- Nach dem Rotieren signiert das alte Geheimnis noch 24 Stunden lang als zweiter v1-Eintrag. Akzeptiere eine Zustellung, wenn irgendein v1 passt.
Berechne den HMAC über den Roh-Body, nicht über eine neu serialisierte Kopie, vergleiche in konstanter Zeit und lehne Zeitstempel ab, die älter als fünf Minuten sind.
import { createHmac, timingSafeEqual } from "node:crypto";
// rawBody: the request body exactly as received, before any JSON parsing.
export function verifyWebhook(header, rawBody, secret, toleranceSec = 300) {
let t = null;
const signatures = [];
for (const item of (header ?? "").split(",")) {
const [key, value] = item.split("=", 2);
if (key === "t") t = Number(value);
if (key === "v1") signatures.push(Buffer.from(value, "hex"));
}
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest();
return signatures.some((s) => s.length === expected.length && timingSafeEqual(s, expected));
}
// verifyWebhook(req.headers["x-signature"], rawBody, process.env.WEBHOOK_SECRET)
// Answer 2xx quickly, and skip an X-Event-Id you have already handled.Fehler
Codes und HTTP-Status sind fest; die Meldung ist für Menschen gedacht.
| Code | HTTP | Wann |
|---|---|---|
invalid_request | 400 | Ein Feld fehlt oder liegt außerhalb des zulässigen Bereichs |
unauthorized | 401 | Kein Schlüssel, ein widerrufener Schlüssel oder eine ungültige Signatur |
insufficient_credits | 402 | Das Guthaben deckt die Reservierung nicht |
forbidden_model | 403 | Die Positivliste des Schlüssels enthält dieses Modell oder Tool nicht |
region_not_supported | 403 | Das Modell wird in deiner Region nicht angeboten |
developer_api_closed | 403 | Ein Entwicklerschlüssel, solange die Entwickler-API geschlossen ist; Zugang auf Antrag |
member_connections_paused | 403 | Eine Mitglieder-Anmeldung (MCP, Verbindungscode oder Kommandozeile), solange die Verbindung eigener KI-Agenten pausiert ist |
not_found | 404 | Dieser Auftrag, dieses Preisangebot oder dieser Upload existiert in deinem Konto nicht |
quote_expired | 409 | Das Preisangebot ist älter als 10 Minuten |
price_changed | 409 | Der Preis ist über deine Obergrenze gestiegen |
content_rejected | 422 | Der Inhalt wurde abgelehnt; es wird nichts berechnet |
rate_limited | 429 | Zu viele Anfragen für diesen Schlüssel |
concurrency_limited | 429 | Zu viele laufende Aufträge für dieses Konto |
internal_error | 500 | Bei uns ist etwas schiefgelaufen |
upstream_unavailable | 503 | Das Modell ist nicht verfügbar; versuch es später erneut |
Ein unklares Ergebnis des Modells ist kein Fehler: Der Auftrag meldet den Status unknown und wird geprüft, bevor etwas erneut eingereicht wird.
Limits
- Anfragen
- Standardmäßig 60 pro Minute und Schlüssel.
- Parallelität
- Standardmäßig 3 Aufträge gleichzeitig pro Konto; frag nach, wenn du mehr brauchst.
- Harte Grenze
- Die Kapazität des Modells ist eine harte Grenze. Mehr Schlüssel erhöhen die Parallelität nicht.
Bilder
POST /v1/images/generations nimmt dieselben Header an. Wähle eine Modell-ID nach Stufe und Vorgang; Bearbeitungsmodelle brauchen zusätzlich image_url, Generierungsmodelle lehnen es ab.
| Stufe | Generieren | Bearbeiten |
|---|---|---|
| Image MiniGünstig · Entwurf | qwen-image-2512-lightning | qwen-image-edit-2511-lightning |
| Image FastEmpfohlen | qwen-image-2512 | qwen-image-edit-2511 |
Eine Klartext-Zusammenfassung für Agenten liegt unter /llms.txt.
Limits nach Modell
Die API-Seite jedes Modells enthält die vollständige Tabelle: Wert, Einheit, wer prüft und was bei Überschreitung passiert. GET /v1/models liefert dieselben Limits als JSON.
- ErzwungenWir prüfen es und antworten mit 400, bevor ein Preisangebot erstellt oder etwas reserviert wird.
- Beim LieferantenDer Anbieter prüft es. Ein Auftrag, den er ablehnt, schlägt fehl, und es wird nichts berechnet.
- EmpfohlenNiemand prüft es. Wenn du darunter bleibst, bekommst du bessere Ergebnisse.
| Modell | Wichtigste Limits | Vollständige Tabelle |
|---|---|---|
seedance-2.0-fastSeedance 2.0 Fast | Prompt 2 bis 2.000 Zeichen · 4 bis 15 s · bis zu 9 Referenzbilder · Bilder 300 bis 6.000 px pro Seite | Tabelle öffnen |
seedance-2.0-miniSeedance 2.0 Mini | Prompt 2 bis 2.000 Zeichen · 4 bis 15 s · bis zu 9 Referenzbilder · Bilder 300 bis 6.000 px pro Seite | Tabelle öffnen |
qwen-image-2512Qwen-Image-2512 | Prompt 2 bis 2.000 Zeichen · 1K oder 2K · kein Ausgangsbild | Tabelle öffnen |
qwen-image-2512-lightningQwen-Image-2512 · Lightning 4-step | Prompt 2 bis 2.000 Zeichen · 1K oder 2K · kein Ausgangsbild | Tabelle öffnen |
qwen-image-edit-2511Qwen-Image-Edit-2511 | Prompt 2 bis 2.000 Zeichen · 1K oder 2K · ein Ausgangsbild, JPEG, PNG oder WebP bis 10 MB | Tabelle öffnen |
qwen-image-edit-2511-lightningQwen-Image-Edit-2511 · Lightning | Prompt 2 bis 2.000 Zeichen · 1K oder 2K · ein Ausgangsbild, JPEG, PNG oder WebP bis 10 MB | Tabelle öffnen |
Uploads
POST /v1/uploads liest den Typ aus der Datei selbst. Upload-Links sind 7 Tage gültig.
| Datei | Formate | Größte Datei | Höchstdauer |
|---|---|---|---|
| Bild: Startbild, Referenz oder Ausgangsbild zum Bearbeiten | JPEG, PNG, WebP | 10 MB | – |
| Video: Lippensynchronisation | MP4 | 50 MB | 60 s |
| Audio: Lippensynchronisation | MP3, WAV, M4A | 10 MB | 60 s |
Wir laden nie Bilder von anderen Hosts, daher prüft bei solchen Links der Anbieter die Größe, und ein Auftrag, den er ablehnt, wird nicht berechnet. Dieselben Limits gibt es auch als JSON: GET /v1/models liefert für jedes Modell ein limits-Objekt.
Umstieg von fal, Replicate oder WaveSpeed
Basis-URL und Schlüssel zu ändern reicht nicht: Jede Anfrage braucht außerdem die Modell-ID im Body, einen Idempotency-Key-Header und eine Preisobergrenze (max_credits oder eine quote_id). Der Leitfaden zum Umstieg ordnet jedes Feld für Seedance 2.0 und Qwen-Image zu und listet auf, was sich nicht übernehmen lässt.