Error Handling
The API uses standard HTTP status codes and returns detailed error information in a consistent format.
Error Response Format
{
"error": {
"code": "error_code",
"message": "Human-readable description",
"details": { ... }
},
"meta": {
"request_id": "req_xxxxxxxxxxxx"
}
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
invalid_request | 400 | Malformed request or invalid parameters |
authentication_required | 401 | Missing or invalid API key |
insufficient_permissions | 403 | API key lacks required scope |
subscription_required | 403 | Organization subscription is not active |
quota_exceeded | 403 | Monthly usage quota has been reached |
not_found | 404 | Resource does not exist |
conflict | 409 | Resource already exists or state conflict |
payload_too_large | 413 | File exceeds size or duration limit |
rate_limit_exceeded | 429 | Too many requests |
internal_error | 500 | Server error |
Common Errors
Invalid Request (400)
Returned when request validation fails.
{
"error": {
"code": "invalid_request",
"message": "Validation failed",
"details": {
"field": "url",
"reason": "Must be a valid HTTPS URL"
}
}
}
Authentication Required (401)
Returned when API key is missing or invalid.
{
"error": {
"code": "authentication_required",
"message": "Invalid or missing API key"
}
}
Subscription Required (403)
Returned when the organization doesn't have an active subscription.
{
"error": {
"code": "subscription_required",
"message": "An active subscription is required to perform this action",
"details": {
"subscription_status": "canceled",
"upgrade_url": "https://scribesight.com/user/settings"
}
}
}
Quota Exceeded (403)
Returned when usage limits have been reached.
{
"error": {
"code": "quota_exceeded",
"message": "Monthly transcription quota exceeded",
"details": {
"quota_type": "transcription_minutes",
"limit": 500,
"used": 500,
"resets_at": "2026-02-01T00:00:00Z",
"upgrade_url": "https://scribesight.com/user/settings"
}
}
}
Not Found (404)
Returned when the requested resource doesn't exist.
{
"error": {
"code": "not_found",
"message": "Project not found",
"details": {
"resource_type": "project",
"resource_id": "proj_xxxxxxxxxxxx"
}
}
}
Payload Too Large (413)
Returned when upload exceeds limits.
{
"error": {
"code": "payload_too_large",
"message": "File exceeds maximum size",
"details": {
"reason": "File size (1.5GB) exceeds maximum (1GB)",
"max_file_size_bytes": 1073741824,
"max_duration_minutes": 70
}
}
}
Rate Limit Exceeded (429)
Returned when too many requests are made.
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry after 60 seconds.",
"details": {
"retry_after": 60
}
}
}
Handling Errors
Python Example
import requests
def make_api_request(url, headers):
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.json()["data"]
error = response.json().get("error", {})
if response.status_code == 401:
raise AuthenticationError(error.get("message"))
elif response.status_code == 403:
if error.get("code") == "quota_exceeded":
raise QuotaExceededError(error.get("details"))
raise PermissionError(error.get("message"))
elif response.status_code == 404:
raise NotFoundError(error.get("message"))
elif response.status_code == 429:
retry_after = error.get("details", {}).get("retry_after", 60)
raise RateLimitError(f"Retry after {retry_after} seconds")
else:
raise APIError(error.get("message", "Unknown error"))
JavaScript Example
async function makeApiRequest(url, headers) {
const response = await fetch(url, { headers });
const body = await response.json();
if (response.ok) {
return body.data;
}
const error = body.error || {};
switch (response.status) {
case 401:
throw new AuthenticationError(error.message);
case 403:
if (error.code === "quota_exceeded") {
throw new QuotaExceededError(error.details);
}
throw new PermissionError(error.message);
case 404:
throw new NotFoundError(error.message);
case 429:
const retryAfter = error.details?.retry_after || 60;
throw new RateLimitError(`Retry after ${retryAfter} seconds`);
default:
throw new APIError(error.message || "Unknown error");
}
}
Retry Strategy
For transient errors (5xx, timeouts, rate limits), implement exponential backoff:
import time
import random
def retry_with_backoff(func, max_retries=5):
for attempt in range(max_retries):
try:
return func()
except (RateLimitError, ServerError) as e:
if attempt == max_retries - 1:
raise
# Exponential backoff with jitter
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)