Error Handling

The Banklyze API uses conventional HTTP status codes and structured JSON error responses. This guide covers the error format, every error code, and best practices for retries.

Error Response Format

Every error response returns a JSON object with the following fields:

NameTypeRequiredDescription
detailstringRequiredA human-readable description of the error.
codestringRequiredA machine-readable error code (see Error Codes table below).
errorsarray | nullOptionalAn array of field-level validation errors. Only present for 422 responses.
Error response
{
  "detail": "Deal not found",
  "code": "DEAL_NOT_FOUND",
  "errors": null
}

HTTP Status Codes

The API returns standard HTTP status codes to indicate success or failure:

CodeMeaningDescription
200OKRequest succeeded. Response body contains the result.
201CreatedResource created successfully.
204No ContentRequest succeeded with no response body (e.g., DELETE).
400Bad RequestThe request body or parameters are malformed.
401UnauthorizedMissing or invalid API key / session token.
403ForbiddenAuthenticated but insufficient permissions.
404Not FoundThe requested resource does not exist.
409ConflictA resource with that identifier already exists.
422Unprocessable EntityValidation failed. Check the errors array for details.
429Too Many RequestsRate limit exceeded. Retry after the Retry-After header.
500Internal Server ErrorSomething went wrong on our end. Please retry.

Error Codes

The code field uses one of these machine-readable identifiers:

Error CodeHTTP StatusDescription
VALIDATION_ERROR422One or more request fields failed validation.
AUTH_REQUIRED401No API key or session token was provided.
INVALID_API_KEY401The API key is invalid, revoked, or expired.
FORBIDDEN403You do not have permission to perform this action.
NOT_FOUND404The requested resource was not found.
DEAL_NOT_FOUND404The specified deal does not exist or is not accessible.
DOCUMENT_NOT_FOUND404The specified document does not exist or is not accessible.
DUPLICATE_RESOURCE409A resource with the same unique identifier already exists.
RATE_LIMIT_EXCEEDED429Too many requests. Back off and retry.
QUOTA_EXCEEDED429Your organization has exceeded its usage quota.
PROCESSING_FAILED500Document processing encountered an unrecoverable error.
WEIGHT_SUM_INVALID422Ruleset factor weights do not sum to 100.
INVALID_DECISION422The decision value is not valid for this deal state.

Validation Errors

When a request fails validation (HTTP 422), the errors array contains one entry per invalid field. Each entry has a field name and a message describing the constraint that was violated.

422 Validation error response
{
  "detail": "Validation failed",
  "code": "VALIDATION_ERROR",
  "errors": [
    {
      "field": "business_name",
      "message": "Field required"
    },
    {
      "field": "ein",
      "message": "String should match pattern '^\\d{9}$'"
    }
  ]
}
Always check the errors array when you receive a 422 response. Display field-level messages to your users so they can fix the input.

Rate Limiting

The API enforces per-organization rate limits. Every response includes rate limit headers so you can track your usage:

NameTypeRequiredDescription
X-RateLimit-LimitintegerRequiredMaximum requests allowed in the current window.
X-RateLimit-RemainingintegerRequiredRequests remaining in the current window.
X-RateLimit-ResetintegerRequiredUnix timestamp when the rate limit window resets.
Retry-AfterintegerOptionalSeconds to wait before retrying (only on 429 responses).
429 Rate limit response
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1710350400
Retry-After: 30

{
  "detail": "Rate limit exceeded. Try again in 30 seconds.",
  "code": "RATE_LIMIT_EXCEEDED",
  "errors": null
}
If you consistently hit rate limits, consider batching requests or using webhooks for event-driven workflows instead of polling.

Retry Strategy

Use exponential backoff with jitter for reliable retry logic. Only retry on 429 (rate limited) and 5xx (server errors). Never retry 4xx client errors (except 429) since the request will fail again with the same parameters.

#!/bin/bash
MAX_RETRIES=5
DELAY=1

for i in $(seq 1 $MAX_RETRIES); do
  RESPONSE=$(curl -s -w "\n%{http_code}" \
    -H "Authorization: Bearer $API_KEY" \
    -H "X-Org-Id: $ORG_ID" \
    "https://api.banklyze.com/v1/deals")

  HTTP_CODE=$(echo "$RESPONSE" | tail -1)
  BODY=$(echo "$RESPONSE" | sed '$d')

  if [ "$HTTP_CODE" -lt 400 ]; then
    echo "$BODY"
    exit 0
  fi

  if [ "$HTTP_CODE" -eq 429 ] || [ "$HTTP_CODE" -ge 500 ]; then
    echo "Attempt $i failed ($HTTP_CODE). Retrying in ${DELAY}s..."
    sleep $DELAY
    DELAY=$((DELAY * 2))
    continue
  fi

  # Client error (4xx) — do not retry
  echo "Error $HTTP_CODE: $BODY"
  exit 1
done

echo "Max retries exceeded"
exit 1
For 429 responses, always prefer the Retry-After header over your calculated backoff delay.