Table of contents

Error mapping

Precium API Error Reference

This document provides a comprehensive reference for all error codes, their causes, and recommended resolution steps.

‍

Error Response Format

All API errors follow a consistent JSON structure:

‍

JSON

{
  "__all__": {
    "message": "Descriptive error message",
    "code": "error_code"
  }
}

‍

Field-specific errors:

JSON

{
  "email": {
    "message": "Enter a valid email address",
    "code": "invalid"
  },
  "purchase.currency": {
    "message": "This field is required",
    "code": "required"
  }
}

‍

HTTP Status Codes

StatusDescriptionCommon Causes
200SuccessRequest completed successfully
201CreatedResource created successfully
204No ContentSuccessful deletion
400Bad RequestValidation errors, malformed JSON
401UnauthorizedInvalid or missing API key
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
409ConflictDuplicate request, state conflict
422Unprocessable EntityBusiness logic error
429Too Many RequestsRate limit exceeded
500Internal Server ErrorServer-side error
502Bad GatewayUpstream service unavailable
503Service UnavailableTemporary maintenance

‍

Authentication Errors

invalid_token

‍

HTTP Status: 401

‍

Message: Invalid or expired authentication token

‍

Causes:

  • API key is incorrect
  • API key has been revoked
  • Using sandbox key in production or vice versa

‍

Resolution:

  1. Verify your API key in the dashboard
  2. Ensure you're using the correct environment
  3. Generate a new API key if necessary

‍

missing_authorization

‍

HTTP Status: 401

‍

Message: Authorization header is required

‍

Causes:

  • No Authorization header provided
  • Malformed Authorization header

‍

Resolution:

BASH

# Correct format
-H "Authorization: Bearer YOUR_API_KEY"

# Common mistakes
-H "Authorization: YOUR_API_KEY"  # Missing "Bearer"
-H "Bearer YOUR_API_KEY"          # Missing "Authorization:"

‍

Validation Errors

required

‍

HTTP Status: 400

‍

Message: This field is required

‍

Example:

JSON

{
  "brand_id": {
    "message": "This field is required",
    "code": "required"
  }
}

‍

Resolution: Include all required fields in your request.

‍

invalid

‍

HTTP Status: 400

‍

Message: Invalid value for this field

‍

Common Cases:

FieldValid FormatExample Error
emailValid emailinvalid_email@
currencyISO 4217 (3 chars)RAND instead of ZAR
phoneE.164 format0821234567 instead of +27821234567
countryISO 3166-1 alpha-2South Africa instead of ZA

‍

invalid_uuid

‍

HTTP Status: 400

‍

Message: Invalid UUID format

‍

Causes:

  • client_id or brand_id is not a valid UUID
  • UUID contains invalid characters

‍

Valid UUID format:

3fa85f64-5717-4562-b3fc-2c963f66afa6

‍

max_length

‍

HTTP Status: 400

‍

Message: Ensure this field has no more than X characters

‍

Field Limits:

FieldMax Length
reference128
purchase.products[].name256
success_redirect500
cardholder_name30
card_number19

‍

min_value / max_value

‍

HTTP Status: 400

‍

Message: Ensure this value is greater/less than X

‍

Amount Limits:

FieldMinMax
purchase.products[].price09,999,999,999
purchase.total_override0999,999,999,999,999

‍

Purchase Errors

purchase_not_found

‍

HTTP Status: 404

‍

Message: Purchase not found

‍

Causes:

  • Invalid purchase ID
  • The purchase belongs to a different merchant
  • Purchase has been deleted

‍

Resolution:

  1. Verify the purchase ID is correct
  2. Ensure you're using the correct API key

‍

purchase_already_paid

‍

HTTP Status: 409

‍

Message: Purchase has already been paid

‍

Causes:

  • Attempting to charge an already-completed purchase
  • Duplicate payment submission

‍

Resolution:

  • Check purchase status before charging
  • Implement idempotency in your integration

‍

purchase_cancelled

‍

HTTP Status: 409

‍

Message: Purchase has been cancelled

‍

Causes:

  • Attempting to charge a cancelled purchase
  • Purchase expired and was auto-cancelled

‍

Resolution:

  • Create a new purchase for the transaction

‍

purchase_expired

‍

HTTP Status: 409

‍

Message: Purchase has expired

‍

Causes:

  • due the date has passed with due_strict: true
  • Direct post URL has expired (15-minute validity)

‍

Resolution:

  • Create a new purchase
  • Process payments promptly after creation

‍

invalid_amount

‍

HTTP Status: 400

‍

Message: Invalid amount specified

‍

Causes:

  • Negative amount
  • Amount exceeds original purchase
  • Zero amount for non-authorization purchase

‍

Resolution:

  • Ensure the amount is positive
  • For partial captures/refunds, ensure the amount ≤ remaining

‍

capture_not_allowed

‍

HTTP Status: 409

‍

Message: Capture is not allowed for this purchase

‍

Causes:

  • Purchase was not created with skip_capture: true
  • Purchase is not in hold status
  • Authorization has expired

‍

Resolution:

  • Verify the purchase status is hold
  • Create a new purchase with skip_capture: true for pre-auth

‍

refund_exceeds_amount

‍

HTTP Status: 400

‍

Message: Refund amount exceeds available balance

‍

Causes:

  • Refund amount greater than the original payment
  • Previous refunds have reduced the available balance

‍

Resolution:

PYTHON

# Check available refund amount
purchase = get_purchase(purchase_id)
available = purchase['purchase']['total'] - purchase.get('refunded_amount', 0)

‍

Payment Method Errors

payment_method_not_available

‍

HTTP Status: 400

‍

Message: Payment method not available

‍

Causes:

  • Payment method not enabled for your merchant
  • Payment method not supported for the currency
  • Payment method excluded by payment_method_whitelist

‍

Resolution:

  1. Check the enabled payment methods
  2. Verify currency support for the payment method
  3. Review payment_method_whitelist in request

‍

recurring_token_not_found

‍

HTTP Status: 404

‍

Message: Recurring token not found

‍

Causes:

  • Invalid token ID
  • Token has been deleted
  • The token belongs to a different client

‍

Resolution:

  1. List client tokens: GET /clients/{id}/recurring_tokens/
  2. Verify the token ID is correct
  3. Re-tokenize if necessary

‍

recurring_token_expired

‍

HTTP Status: 409

‍

Message: Recurring token has expired

‍

Causes:

  • The card has expired
  • Token validity period exceeded
  • Mandate expired (DebiCheck)

‍

Resolution:

  • Request the customer to re-tokenize payment method

‍

card_declined

‍

HTTP Status: 422

‍

Message: Card was declined

‍

Decline Reasons:

CodeDescriptionCustomer Action
do_not_honourGeneric declineTry different card
insufficient_fundsNot enough balanceAdd funds or use different card
expired_cardCard has expiredUse valid card
invalid_cardCard number invalidCheck card details
lost_stolenCard reported lost/stolenContact bank
suspected_fraudFraud suspicionContact bank

‍

3ds_authentication_failed

‍

HTTP Status: 422

‍

Message: 3D Secure authentication failed

‍

Causes:

  • Customer failed 3DS challenge
  • 3DS timeout
  • Customer cancelled authentication

‍

Resolution:

  • The customer should retry with the correct credentials
  • Ensure the 3DS page loads correctly

‍

Client Errors

client_not_found

‍

HTTP Status: 404

‍

Message: Client not found

‍

Resolution:

  1. Verify client ID is correct
  2. Create a client if it doesn't exist

‍

duplicate_client

‍

HTTP Status: 409

‍

Message: Client with this email already exists

‍

Causes:

  • Attempting to create a client with an existing email

‍

Resolution:

  • Search for existing client: GET /clients/?email=customer@example.com
  • Use existing client ID

‍

Billing Template Errors

billing_template_not_found

‍

HTTP Status: 404

‍

Message: Billing template not found

‍

subscriber_already_exists

‍

HTTP Status: 409

‍

Message: Client is already subscribed to this template

‍

Resolution:

  • Check existing subscription status
  • Update existing subscription instead of creating new one

‍

subscription_inactive

‍

HTTP Status: 409

‍

Message: Subscription is not active

‍

Causes:

  • subscription_active: false on template
  • Subscription has been cancelled

‍

Webhook Errors

webhook_url_invalid

‍

HTTP Status: 400

‍

Message: Invalid webhook URL

‍

Requirements:

  • Must be HTTPS
  • Must be publicly accessible
  • Must respond within 5 seconds

‍

webhook_url_unreachable

‍

HTTP Status: 400

‍

Message: Webhook URL is not reachable

‍

Resolution:

  1. Verify URL is publicly accessible
  2. Check firewall rules
  3. Ensure the SSL certificate is valid

‍

Rate Limiting Errors

rate_limit_exceeded

‍

HTTP Status: 429

‍

Message: Rate limit exceeded

‍

Response Headers:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1619740860

‍

Resolution:

  1. Implement exponential backoff
  2. Cache responses where possible
  3. Batch operations when available

‍

Retry Logic:

PYTHON

import time

def api_request_with_retry(func, max_retries=3):
    for attempt in range(max_retries):
        response = func()
        if response.status_code != 429:
            return response

        reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
        wait_time = max(reset_time - time.time(), 2 ** attempt)
        time.sleep(wait_time)

    raise Exception("Rate limit exceeded after retries")

‍

Direct Post Errors

direct_post_expired

‍

HTTP Status: 400

‍

Message: Direct post URL has expired

‍

Causes:

  • URL validity is 15 minutes
  • URL has already been used

‍

Resolution:

  • Create a new purchase for the fresh direct post URL

‍

invalid_card_data

‍

HTTP Status: 400

‍

Message: Invalid card data submitted

‍

Field Validation:

FieldValidationError
cardholder_nameLatin letters, space, apostrophe, dot, dashNon-Latin characters
card_numberDigits only, valid LuhnInvalid format
expiresMM/YY format, future datePast date or invalid format
cvc3-4 digitsInvalid length

‍

Error Handling Best Practices

1. Always Check HTTP Status

PYTHON

response = requests.post(url, json=data, headers=headers)

if response.status_code == 201:
    # Success - process response
    purchase = response.json()
elif response.status_code == 400:
    # Validation error - show user-friendly message
    errors = response.json()
    handle_validation_errors(errors)
elif response.status_code == 401:
    # Auth error - check credentials
    refresh_credentials()
elif response.status_code == 429:
    # Rate limited - retry with backoff
    retry_with_backoff()
else:
    # Other error - log and alert
    log_error(response)

‍

2. Display User-Friendly Messages

PYTHON

ERROR_MESSAGES = {
    'card_declined': 'Your card was declined. Please try a different payment method.',
    'insufficient_funds': 'Insufficient funds. Please use a different card.',
    'expired_card': 'Your card has expired. Please use a valid card.',
    '3ds_authentication_failed': 'Authentication failed. Please try again.',
    'invalid': 'Please check your information and try again.'
}

def get_user_message(error_code):
    return ERROR_MESSAGES.get(error_code, 'An error occurred. Please try again.')

‍

3. Log Errors for Debugging

PYTHON

import logging

def log_api_error(response, request_data):
    logging.error(
        "API Error",
        extra={
            'status_code': response.status_code,
            'response_body': response.text,
            'request_url': response.url,
            'request_data': sanitize_sensitive_data(request_data)
        }
    )

‍

4. Implement Retry Logic

PYTHON

from tenacity import retry, stop_after_attempt, wait_exponential

@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=2, max=10),
    retry=lambda e: isinstance(e, RetryableError)
)
def make_api_request():
    response = requests.post(...)
    if response.status_code in [429, 502, 503]:
        raise RetryableError()
    return response

‍

Error Code Quick Reference

CodeHTTPCategoryAction
invalid_token401AuthCheck API key
required400ValidationAdd missing field
invalid400ValidationFix field format
purchase_not_found404ResourceVerify ID
purchase_already_paid409StateCheck status first
card_declined422PaymentTry different card
insufficient_funds422PaymentTry different card
3ds_authentication_failed422PaymentRetry authentication
recurring_token_expired409TokenRe-tokenize
rate_limit_exceeded429Rate LimitImplement backoff