Wie Fehler gemeldet werden
Jeder Fehler der Sally API nutzt denselben JSON-Body, ein Fehler-Handler reicht also. Diese Seite zeigt diesen Body, was jeder Statuscode für deine Anbindung bedeutet, jeden maschinenlesbaren code, einen Beispiel-Body je Status und einen Handler zum Kopieren.
Die Beispiele funktionieren so, wie sie dastehen, sobald SALLY_TOKEN und DIRECTORY_ID gesetzt sind, siehe Schnellstart.
Schnellnavigation
- Der Fehler-Body
- Die Statuscodes
- Die Fehlercodes
- Beispiel-Bodys
- 403 und 404 bedeuten Verschiedenes
- Fehler im Code behandeln
1. Der Fehler-Body
{
"statusCode": 429,
"message": "<für Menschen lesbarer Text>",
"code": "FUP_LIMIT_EXCEEDED"
}
| Feld | Typ | Immer da | Bedeutung |
|---|---|---|---|
statusCode | integer | ja | Der HTTP-Statuscode, im Body wiederholt. |
message | string | ja | Eine für Menschen lesbare Beschreibung. Zeig oder logge sie, aber verzweige nicht darauf. |
code | string | nein | Eine stabile, maschinenlesbare Kennung für bestimmte Fehler. |
code ist eine stabile, maschinenlesbare Kennung. Sie steht nur bei Fehlern, die eine eigene Reaktion verdienen, etwa FUP_LIMIT_EXCEEDED oder TOO_MANY_CONCURRENT_TRANSCRIPTIONS. Allgemeine Fehler lassen sie weg. Verzweige also auf code, wenn er da ist, sonst auf statusCode.
Der Text von message ist für Menschen gedacht, kann sich ändern und ist unter Umständen deutsch. Echte Antworten können zusätzlich ein Feld error mit der HTTP-Statusbezeichnung tragen, etwa Unauthorized. Es gehört nicht zum dokumentierten Body, verlass dich also nicht darauf.
2. Die Statuscodes
| Code | Bedeutung | Was du tust | Erneut versuchen? |
|---|---|---|---|
400 | Die Anfrage ist ungültig: Body, Query oder Pfad haben die Prüfung nicht bestanden. | Korrigier die Anfrage, etwa einen falsch geschriebenen Namen in fields. | Nein |
401 | Das Bearer-Token fehlt oder ist nicht mehr gültig. | Prüf den Header Authorization oder leg ein neues Token an. | Nein |
403 | Du siehst die Ressource, aber die Operation verlangt eine höhere Rolle, etwa Admin oder Owner, oder das Unternehmenskonto hat sie gesperrt, etwa einen Download. Hier lohnt der Blick auf code. | Nimm das Token eines Nutzers mit der nötigen Rolle oder lass die Einstellung des Unternehmenskontos ändern. | Nein |
404 | Nicht gefunden oder für dich nicht sichtbar. | Prüf die Id und ob der Nutzer des Tokens Zugriff hat. | Nein |
409 | Konflikt mit dem aktuellen Stand, etwa beim Einladen einer Person, die schon Mitglied ist, oder wenn du ein Transkript als Datei anforderst, bevor es existiert. Hier lohnt der Blick auf code. | Behandle es als bereits erledigt oder lies den aktuellen Stand. | Nein |
429 | Rate-Limit überschritten, bei Uploads auch die Fair-Usage-Grenze. Hier lohnt der Blick auf code. | Siehe Limits und Fair Usage. | Hängt von code ab |
500 | Interner Serverfehler. Später erneut zu versuchen ist sinnvoll. | Versuch es später mit wachsender Pause erneut. | Ja |
3. Die Fehlercodes
Das sind alle Werte, die code annehmen kann. Verzweige darauf, sie ändern sich nicht.
code | Status | Wo | Bedeutung und was du tust |
|---|---|---|---|
UNKNOWN_DOCUMENT_FORMAT | 400 | Zusammenfassung und Transkript als Datei | format fehlt oder wird von diesem Endpunkt nicht unterstützt. Der Body nennt die erlaubten Werte. |
UNKNOWN_LANGUAGE_CODE | 400 | Zusammenfassung und Transkript als Datei | languageCode ist unbekannt. Der Body nennt die erlaubten Werte. |
SUMMARY_DOWNLOAD_PREVENTED | 403 | Zusammenfassung als Datei | Das Unternehmenskonto hat den Download von Zusammenfassungen für seine Mitglieder gesperrt. Ein erneuter Versuch bringt dieselbe Antwort. |
TRANSCRIPT_DOWNLOAD_PREVENTED | 403 | Transkript als Datei | Das Unternehmenskonto hat den Download von Transkripten für seine Mitglieder gesperrt. Ein erneuter Versuch bringt dieselbe Antwort. |
RECORDING_EXISTS_CHOICE_REQUIRED | 409 | Upload abschließen | Der verknüpfte Termin hat schon eine Aufnahme. Wiederhole den Aufruf mit choice auf copy oder replace, die hochgeladene Datei bleibt erhalten. |
SUMMARY_HAS_NO_CONTENT | 409 | Zusammenfassung als Datei | Die Zusammenfassung hat keinen Inhalt für ein Dokument, weil sie entstand, bevor es Meetingtemplates gab, oder ihr Template keine Abschnitte hat. |
TRANSCRIPT_NOT_AVAILABLE | 409 | Transkript als Datei | Die Aufnahme hat noch kein Transkript. Prüf vorher isTranscriptionSucceeded an der Aufnahme. |
FUP_LIMIT_EXCEEDED | 429 | Uploads | Die Fair-Usage-Grenze ist ausgeschöpft. Hör mit dem Hochladen auf, ein baldiger neuer Versuch bringt dieselbe Antwort. Siehe Limits und Fair Usage. |
TOO_MANY_CONCURRENT_TRANSCRIPTIONS | 429 | Uploads | Im Unternehmenskonto laufen zu viele Transkriptionen gleichzeitig. Warte, bis einige fertig sind. |
4. Beispiel-Bodys
Diese Bodys kannst du je Status erwarten. Wo das Beispiel <für Menschen lesbarer Text> zeigt, hängt die echte message von der Ursache ab.
400, etwa bei einem unbekannten Feldnamen:
{
"statusCode": 400,
"message": "<für Menschen lesbarer Text>"
}
401, Anfrage ohne Token und Anfrage mit ungültigem Token. Diese beiden sind echte Antworten der API:
{
"message": "`Authorization: Bearer <token>` ist erforderlich.",
"error": "Unauthorized",
"statusCode": 401
}
{
"message": "Ungültiger oder abgelaufener API-Key.",
"error": "Unauthorized",
"statusCode": 401
}
403, die Operation verlangt eine höhere Rolle:
{
"statusCode": 403,
"message": "<für Menschen lesbarer Text>"
}
403 mit code, etwa wenn das Unternehmenskonto den Download von Zusammenfassungen gesperrt hat:
{
"statusCode": 403,
"message": "<für Menschen lesbarer Text>",
"code": "SUMMARY_DOWNLOAD_PREVENTED"
}
404, nicht gefunden oder nicht sichtbar:
{
"statusCode": 404,
"message": "<für Menschen lesbarer Text>"
}
409, etwa wenn die eingeladene Person schon Mitglied ist:
{
"statusCode": 409,
"message": "<für Menschen lesbarer Text>"
}
429 gibt es in drei Varianten. Das einfache Rate-Limit hat keinen code, die beiden Fair-Usage-Fälle schon:
{
"statusCode": 429,
"message": "<für Menschen lesbarer Text>"
}
{
"statusCode": 429,
"message": "<für Menschen lesbarer Text>",
"code": "FUP_LIMIT_EXCEEDED"
}
{
"statusCode": 429,
"message": "<für Menschen lesbarer Text>",
"code": "TOO_MANY_CONCURRENT_TRANSCRIPTIONS"
}
500, interner Serverfehler:
{
"statusCode": 500,
"message": "<für Menschen lesbarer Text>"
}
5. 403 und 404 bedeuten Verschiedenes
Ein 403 sagt dir, dass die Ressource existiert und deine Rolle zu niedrig ist oder das Unternehmenskonto die Operation gesperrt hat, was ein Mensch beheben kann. Ein 404 sagt dir absichtlich nichts: Nicht gefunden und nicht sichtbar sind bewusst nicht unterscheidbar, damit eine Antwort nie verrät, dass es Daten gibt. Warum ein Token sieht, was es sieht, erklärt Authentifizierung.
| 403 Forbidden | 404 Not Found | |
|---|---|---|
| Gibt es die Ressource? | Ja | Unbekannt, mit Absicht |
| Siehst du sie? | Ja | Nicht mit diesem Token |
| Wer kann es beheben? | Ein Admin oder Owner, indem er dem Nutzer eine höhere Rolle gibt oder die Einstellung des Unternehmenskontos ändert | Niemand über die API. Prüf die Id und den Zugriff des Token-Nutzers. |
6. Fehler im Code behandeln
Lies bei jeder Antwort außerhalb von 2xx den Body und entscheide zuerst nach code, dann nach statusCode:
- cURL
- JavaScript
- Python
# Body und Status getrennt, dann nach code und statusCode entscheiden
response=$(curl -s -w '\n%{http_code}' \
"https://api.sally.io/v1.0/directories/$DIRECTORY_ID/recordings/$RECORDING_ID" \
-H "Authorization: Bearer $SALLY_TOKEN")
status=$(echo "$response" | tail -n 1)
body=$(echo "$response" | sed '$d')
if [ "$status" -ge 400 ]; then
echo "$body" | jq -r '"\(.statusCode) \(.code // "-") \(.message)"'
fi
class SallyApiError extends Error {
constructor(status, body) {
super(body?.message ?? `HTTP ${status}`);
this.statusCode = body?.statusCode ?? status;
this.code = body?.code ?? null;
}
}
async function sally(path, init = {}) {
const response = await fetch(`https://api.sally.io${path}`, {
...init,
headers: {Authorization: `Bearer ${process.env.SALLY_TOKEN}`, ...init.headers},
});
if (response.ok) return response.status === 204 ? null : response.json();
const body = await response.json().catch(() => null);
throw new SallyApiError(response.status, body);
}
try {
const recording = await sally(`/v1.0/directories/${directoryId}/recordings/${recordingId}`);
} catch (error) {
if (!(error instanceof SallyApiError)) throw error;
if (error.code === 'FUP_LIMIT_EXCEEDED') {
// Kontingent aufgebraucht: Uploads stoppen, ein baldiger Versuch bringt dieselbe Antwort
} else if (error.code === 'TOO_MANY_CONCURRENT_TRANSCRIPTIONS') {
// warten, bis laufende Transkriptionen fertig sind
} else if (error.statusCode === 401) {
// Token fehlt oder ist ungültig
} else if (error.statusCode === 404) {
// nicht gefunden oder nicht sichtbar
} else if (error.statusCode === 429 || error.statusCode >= 500) {
// später mit wachsender Pause erneut versuchen
} else {
throw error; // 400, 403, 409: Anfrage korrigieren
}
}
import os
import requests
class SallyApiError(Exception):
def __init__(self, status, body):
body = body or {}
super().__init__(body.get("message", f"HTTP {status}"))
self.status_code = body.get("statusCode", status)
self.code = body.get("code")
def sally(method, path, **kwargs):
response = requests.request(
method,
f"https://api.sally.io{path}",
headers={"Authorization": f"Bearer {os.environ['SALLY_TOKEN']}"},
**kwargs,
)
if response.ok:
return response.json() if response.status_code != 204 else None
try:
body = response.json()
except ValueError:
body = None
raise SallyApiError(response.status_code, body)
try:
recording = sally("GET", f"/v1.0/directories/{directory_id}/recordings/{recording_id}")
except SallyApiError as error:
if error.code == "FUP_LIMIT_EXCEEDED":
pass # Kontingent aufgebraucht: Uploads stoppen, ein baldiger Versuch bringt dieselbe Antwort
elif error.code == "TOO_MANY_CONCURRENT_TRANSCRIPTIONS":
pass # warten, bis laufende Transkriptionen fertig sind
elif error.status_code == 401:
pass # Token fehlt oder ist ungültig
elif error.status_code == 404:
pass # nicht gefunden oder nicht sichtbar
elif error.status_code == 429 or error.status_code >= 500:
pass # später mit wachsender Pause erneut versuchen
else:
raise # 400, 403, 409: Anfrage korrigieren
Logge statusCode, code und message zusammen mit Methode und Pfad der Anfrage. Das reicht meist, um die Ursache zu finden, ohne den Aufruf nachzustellen.