Skip to main content

Error response format

When an error occurs, the API returns a JSON response with an error object:
{
  "error": {
    "type": "invalid_request_error",
    "code": "insufficient_balance",
    "message": "Customer does not have sufficient balance for this operation",
    "param": "amount_cents",
    "doc_url": "https://docs.bipa.tech/errors#insufficient_balance"
  }
}

Error object fields

FieldTypeDescription
typestringThe category of error
codestringA specific error code for programmatic handling
messagestringA human-readable description of the error
paramstringThe parameter that caused the error (when applicable)
doc_urlstringLink to documentation about this error

HTTP status codes

StatusDescription
200Success
201Resource created
400Bad request — invalid parameters
401Unauthorized — invalid or missing API key
403Forbidden — insufficient permissions
404Not found — resource doesn’t exist
409Conflict — duplicate idempotency key
422Unprocessable — valid request but cannot be completed
429Too many requests — rate limit exceeded
500Internal server error

Error types

invalid_request_error

The request was malformed or missing required parameters.
{
  "error": {
    "type": "invalid_request_error",
    "code": "missing_required_field",
    "message": "The 'document' field is required",
    "param": "document"
  }
}

authentication_error

The API key is invalid, missing, or revoked.
{
  "error": {
    "type": "authentication_error",
    "code": "invalid_api_key",
    "message": "The API key provided is invalid or has been revoked."
  }
}

rate_limit_error

Too many requests in a short period.
{
  "error": {
    "type": "rate_limit_error",
    "code": "too_many_requests",
    "message": "Rate limit exceeded. Please retry after 60 seconds."
  }
}

api_error

An internal error occurred on Bipa’s servers.
{
  "error": {
    "type": "api_error",
    "code": "internal_error",
    "message": "An unexpected error occurred. Please try again."
  }
}

Common error codes

Customer errors

CodeDescription
customer_not_foundThe specified customer ID doesn’t exist
customer_inactiveThe customer account has been deactivated
duplicate_documentA customer with this CPF/CNPJ already exists
invalid_documentThe CPF or CNPJ number is invalid

Balance errors

CodeDescription
insufficient_balanceNot enough funds to complete the operation
balance_lockedFunds are temporarily locked (pending transactions)

Quote errors

CodeDescription
quote_expiredThe quote has expired and cannot be executed
quote_already_executedThis quote has already been used
invalid_currency_pairThe currency pair is not supported
amount_too_smallThe amount is below the minimum allowed
amount_too_largeThe amount exceeds the maximum allowed

Pix errors

CodeDescription
pix_key_not_foundThe destination Pix key doesn’t exist
pix_key_inactiveThe Pix key has been deactivated
pix_limit_exceededTransaction exceeds Pix limits
invalid_pix_key_typeThe Pix key type is not valid

Transfer errors

CodeDescription
invalid_addressThe destination address is invalid
unsupported_networkThe specified network is not supported
withdrawal_disabledWithdrawals are temporarily disabled

Idempotency errors

CodeDescription
duplicate_idempotency_keyThis idempotency key was already used with different parameters

Handling errors

import requests

try:
    response = requests.post(
        "https://api.bipa.tech/v1/customers",
        headers={"Authorization": "Bearer bipa_live_sk_..."},
        json={"type": "individual", "name": "João"}
    )
    response.raise_for_status()
    customer = response.json()
except requests.exceptions.HTTPError as e:
    error = e.response.json().get("error", {})

    if error.get("code") == "duplicate_document":
        # Customer already exists, retrieve instead
        pass
    elif error.get("type") == "rate_limit_error":
        # Wait and retry
        time.sleep(60)
    else:
        # Log and handle other errors
        print(f"API error: {error.get('message')}")

Retry strategy

For transient errors (5xx status codes and rate limits), implement exponential backoff:
import time
import random

def api_request_with_retry(url, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, headers=headers)

        if response.status_code == 200:
            return response.json()

        if response.status_code == 429 or response.status_code >= 500:
            # Exponential backoff with jitter
            delay = (2 ** attempt) + random.uniform(0, 1)
            time.sleep(delay)
            continue

        # Non-retryable error
        response.raise_for_status()

    raise Exception("Max retries exceeded")
Don’t retry 4xx errors (except 429). These indicate client-side issues that won’t resolve by retrying.