Error Handling

Understand Svara API error responses, error codes, and how to handle failures gracefully.

Error response format

When a request fails, the API returns a JSON error response with a consistent structure:

{
  "error": {
    "code": "invalid_parameter",
    "message": "The 'platform' field must be one of: linkedin, telegram, whatsapp.",
    "details": {
      "field": "platform",
      "value": "twitter"
    }
  }
}

| Field | Type | Description | |---|---|---| | error.code | string | Machine-readable error code for programmatic handling | | error.message | string | Human-readable description of what went wrong | | error.details | object | Additional context (varies by error type, may be null) |

HTTP status codes

| Status | Code | Description | Common causes | |---|---|---|---| | 400 | bad_request | The request body is malformed or missing required fields | Invalid JSON, missing platform or recipient field | | 401 | unauthorized | The API key is missing, invalid, or revoked | No Authorization header, wrong key, expired key | | 402 | payment_required | Your account has exceeded its monthly usage limit | Upgrade your plan or wait for the next billing period | | 404 | not_found | The requested resource does not exist | Invalid message ID in status check, wrong endpoint URL | | 413 | payload_too_large | The audio file exceeds the maximum size limit | LinkedIn: 10 MB max, Telegram: 50 MB max | | 422 | unprocessable_entity | The request is well-formed but contains invalid values | Invalid audio URL, unsupported format, bad session data | | 429 | rate_limited | Too many requests in the current time window | Exceeded your plan's per-minute rate limit | | 500 | internal_error | An unexpected error occurred on the server | Transient issue — safe to retry with backoff | | 502 | platform_error | The target platform returned an error | Platform outage, session expired, recipient unavailable |

Handling errors in code

JavaScript

const response = await fetch("https://api.svarapi.io/v1/send", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SVARA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify(payload),
});

if (!response.ok) {
  const { error } = await response.json();

  switch (response.status) {
    case 401:
      throw new Error("Invalid API key — check your SVARA_API_KEY");
    case 402:
      throw new Error("Usage limit exceeded — upgrade your plan");
    case 429:
      const retryAfter = response.headers.get("Retry-After");
      console.log(`Rate limited. Retry after ${retryAfter} seconds`);
      break;
    case 502:
      console.error(`Platform error: ${error.message}`);
      // Retry with backoff for transient platform issues
      break;
    default:
      console.error(`API error ${response.status}: ${error.message}`);
  }
}

Python

import requests
import time

response = requests.post(
    "https://api.svarapi.io/v1/send",
    headers={"Authorization": f"Bearer {api_key}"},
    json=payload,
)

if response.status_code == 429:
    retry_after = int(response.headers.get("Retry-After", 60))
    print(f"Rate limited. Retrying in {retry_after} seconds.")
    time.sleep(retry_after)
elif response.status_code == 502:
    error = response.json()["error"]
    print(f"Platform error: {error['message']}")
elif not response.ok:
    error = response.json()["error"]
    raise Exception(f"Svara API error ({error['code']}): {error['message']}")

Retry strategy

For transient errors (429, 500, 502), implement exponential backoff:

  1. Wait 1 second, then retry.
  2. If it fails again, wait 2 seconds.
  3. Double the wait time on each subsequent failure, up to a maximum of 60 seconds.
  4. Give up after 5 attempts and log the failure.
async function sendWithRetry(payload, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch("https://api.svarapi.io/v1/send", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.SVARA_API_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify(payload),
    });

    if (response.ok) return response.json();

    const retryable = [429, 500, 502].includes(response.status);
    if (!retryable) {
      const { error } = await response.json();
      throw new Error(`${error.code}: ${error.message}`);
    }

    const delay = Math.min(1000 * Math.pow(2, attempt), 60000);
    await new Promise((resolve) => setTimeout(resolve, delay));
  }

  throw new Error("Max retries exceeded");
}

Rate limiting details

When you hit the rate limit, the response includes a Retry-After header with the number of seconds to wait:

HTTP/2 429
Content-Type: application/json
Retry-After: 12
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710422472

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded. Retry after 12 seconds.",
    "details": {
      "limit": 100,
      "window": "1m",
      "retry_after": 12
    }
  }
}

See Rate Limits for per-plan limits and best practices.

Ask Svara

Hey! I'm the Svara assistant. Ask me anything about integrating voice notes into your product.

Powered by Svara