uAPI uses conventional HTTP statuses and a stable error.code and error.message inside the envelope. Always read the HTTP status, then inspect the JSON body. The SDKs surface these errors as typed exceptions while preserving the underlying envelope for debugging.
The Python SDK raises typed exceptions that wrap the uAPI envelope.
Copy
import osimport uapifrom uapi import uAPIclient = uAPI(api_key=os.environ.get("UAPI_API_KEY"))try: resp = client.extract(url="https://invalid") # On success, resp is a typed model with .data, .error, etc. print(resp.to_dict())except uapi.APIConnectionError as e: # Network, DNS, TLS, or timeout issues print("uAPI connection error:", e)except uapi.RateLimitError as e: # 429 Too Many Requests print("Rate limited, back off:", e)except uapi.APIStatusError as e: # Any non-2xx with a uAPI envelope body = e.response.json() if e.response is not None else {} code = body.get("error", {}).get("code") rid = body.get("id") print(f"uAPI error {code} (status={e.status_code}, request_id={rid})")except uapi.APIError as e: # Fallback for any other library-specific error print("Unexpected uAPI error:", e)
Behavior:
uAPI returns conventional HTTP statuses and envelope fields.
The SDK maps them to:
400-series and 500-series → subclasses of uapi.APIStatusError (e.g. BadRequestError, AuthenticationError, PermissionDeniedError, RateLimitError, InternalServerError).
Connection/timeout issues → APIConnectionError.
All share uapi.APIError as a common base type.
The TypeScript SDK throws APIError subclasses for non-2xx and connection issues.
Copy
import 'dotenv/config'import uAPI from 'usdk-js'const client = new uAPI({ apiKey: process.env['UAPI_API_KEY'],})try { const result = await client.extract({ url: 'https://invalid' }) console.log(result)} catch (err) { if (err instanceof uAPI.APIError) { // HTTP status when available console.error('status:', err.status) console.error('name:', err.name) // e.g. BadRequestError, AuthenticationError console.error('headers:', err.headers) // Envelope body (if returned) is available via err.body or err.message content // Use this to read error.code and request.id when needed. } else { // Non-uAPI error (e.g. coding bug) throw err }}
The SDK:
Surfaces 4xx/5xx as typed APIError variants with status, name, and headers.
Retries connection and selected 4xx/5xx errors by default with backoff.
Keeps your application logic focused on handling known failure modes.
If you are not using an SDK, always:
Check res.status.
Parse the JSON.
If success is false, use error.code for branching and error.message and id for logs and support.
Copy
import os, requestsr = requests.get( "https://api.uapi.nl/v1/extract", params={"url": "https://invalid"}, headers={"X-API-Key": os.environ["UAPI_API_KEY"]}, timeout=30)body = r.json()if not r.ok or body.get("success") is False: code = (body.get("error") or {}).get("code") msg = (body.get("error") or {}).get("message") rid = body.get("id") raise RuntimeError(f"uAPI error {code}: {msg} (request {rid})")
Use the SDKs wherever possible so transport issues, retries, and status mapping are handled consistently. In all environments, rely on:
HTTP status for coarse-grained control.
error.code for branching logic.
id and request fields for logging, observability, and support.