Table of contents

Troubleshooting

Precium API Troubleshooting Guide

Solutions to common integration issues and debugging techniques.

‍

Quick Diagnostics

API Health Check

BASH

curl -X GET "https://gate.reviopay.com/api/v1/clients/" \
  -H "Authorization: Bearer YOUR_API_KEY"

‍

ResponseMeaningAction
200 with resultsAPI workingIntegration issue
401 UnauthorizedInvalid API keyCheck credentials
500 Server ErrorPlatform issueContact support
Connection refusedNetwork issueCheck connectivity

‍

Authentication Issues

Problem: 401 Unauthorized

Symptoms:

JSON

{
  "__all__": {
    "message": "Invalid or expired authentication token",
    "code": "invalid_token"
  }
}

‍

Common Causes:

  1. Incorrect API Key

‍

BASH

    # Wrong
    -H "Authorization: your_api_key"

    # Correct
    -H "Authorization: Bearer your_api_key"

‍

  1. Environment Mismatch
  • Using the sandbox key in production
  • Using the production key in the sandbox
  1. Revoked Key
  • The key was regenerated in the dashboard
  • The key was disabled

‍

Resolution:

  1. Verify key format includes "Bearer " prefix
  2. Check that the key in the dashboard matches the configuration
  3. Generate a new key if necessary
  4. Ensure the environment matches

‍

Problem: Missing Authorization Header

Symptoms:

JSON

{
  "__all__": {
    "message": "Authorization header is required",
    "code": "missing_authorization"
  }
}

‍

Resolution:

Ensure every request includes the header:

‍

PYTHON

headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json"
}

‍

Purchase Creation Issues

Problem: Invalid brand_id

Symptoms:

JSON

{
  "brand_id": {
    "message": "Invalid pk \"xxx\" - object does not exist",
    "code": "does_not_exist"
  }
}

‍

Causes:

  • Incorrect brand ID
  • Brand ID from a different environment
  • Typo in UUID

‍

Resolution:

  1. Copy brand_id directly from the dashboard
  2. Verify format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  3. Ensure the use of the correct environment's brand

‍

Problem: checkout_url Not Generated

Symptoms:

  • checkout_url is null in response
  • direct_post_url is null

‍

Causes:

  • Missing success_redirect or failure_redirect
  • purchase.request_client_details is not empty
  • Purchase is not in a payable state

‍

Resolution:

Include redirect URLs:

‍

JSON

{
  "success_redirect": "https://www.example.com/success",
  "failure_redirect": "https://www.example.com/failure",
  ...
}

‍

Problem: Total Amount Mismatch

Symptoms:

  • Calculated total doesn't match expected
  • Checkout shows the wrong amount

‍

Diagnosis:

PYTHON

# Check how total is calculated
total = sum(
    product['price'] * int(product.get('quantity', '1'))
    for product in products
)

‍

Common Issues:

  • Quantity is a string, not applied correctly
  • Discount/tax calculations
  • Override fields not set properly

‍

Resolution:

JSON

{
  "products": [
    {"name": "Item", "price": 5000, "quantity": "2"}  // quantity is STRING
  ],
  "total_override": null  // Don't set unless intentional
}

‍

Payment Processing Issues

Problem: Card Declined

Symptoms:

  • Payment fails at checkout
  • Error message: "Card declined"

‍

Possible Causes:

Decline ReasonMeaningSolution
do_not_honourGeneric declineTry different card
insufficient_fundsNot enough balanceUse different card
expired_cardCard expiredUse valid card
invalid_cardCard number invalidCheck digits
suspected_fraudFraud detectionContact bank

‍

Debugging:

BASH

# Check purchase for detailed error
GET /purchases/{id}/

# Response includes:
{
  "status": "failed",
  "payment_failure_reason": "do_not_honour"
}

‍

Problem: 3DS Authentication Failed

Symptoms:

  • Customer fails 3D Secure challenge
  • Redirect to failure URL
  • Error: 3ds_authentication_failed

‍

Causes:

  • The customer entered the wrong OTP/password
  • 3DS timeout
  • Customer cancelled
  • Browser pop-up blocked

‍

Resolution:

  1. The customer should retry with the correct credentials
  2. Ensure pop-ups are not blocked
  3. Verify redirect URLs load quickly
  4. Check browser compatibility

‍

Problem: Payment Stuck in Pending

Symptoms:

  • Status remains pending_charge indefinitely
  • No success/failure redirect

‍

Diagnosis:

BASH

# Check current status
GET /purchases/{id}/

# Response
{
  "status": "pending",
  "events": [...],  // Check for processing events
  "payment_method_details": {...}
}

‍

Causes:

  • 3DS flow not completed
  • Customer abandoned payment
  • Processing delay

‍

Resolution:

  1. Wait for processing (usually < 60 seconds)
  2. Check if the customer completed 3DS
  3. Set up webhooks for async notification
  4. For extended pending, contact support

‍

Webhook Issues

Problem: Webhooks Not Received

Checklist:

  • Webhook URL is HTTPS
  • URL is publicly accessible
  • Firewall allows Precium IPs
  • Server responds within 5 seconds
  • Events are subscribed to

‍

Debug Steps:

  1. Verify webhook configuration:

‍

BASH

GET /webhooks/

# Check your endpoints are listed

‍

  1. Test URL accessibility:

‍

BASH

curl -X POST "https://www.example.com/webhooks/precium" \
  -H "Content-Type: application/json" \
  -d '{"test": true}'

‍

  1. Check server logs for incoming requests
  2. Verify the SSL certificate is valid

‍

Problem: Webhook Signature Invalid

Symptoms:

  • Signature verification fails
  • Events appear legitimate, but don't validate

‍

Debug:

PYTHON

import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding

# Signing is ASYMMETRIC RSA — there is no shared secret to compare against.
# The two most common causes of a failure here are verifying a re-serialised
# body instead of the raw bytes, and using the wrong public key.

def debug_signature(raw_body: bytes, received_sig: str, public_key_pem: str) -> bool:
    print(f"X-Signature: {received_sig}")
    print(f"Raw body length: {len(raw_body)} bytes")
    key = serialization.load_pem_public_key(public_key_pem.encode())
    try:
        key.verify(
            base64.b64decode(received_sig),
            raw_body,
            padding.PKCS1v15(),
            hashes.SHA256(),
        )
        print("Valid")
        return True
    except Exception as exc:
        print(f"Invalid: {exc}")
        print("Check: raw bytes (not json.dumps output)? correct key for this webhook?")
        return False

‍

Common Issues:

  1. Payload modification: Use raw request body

‍

PYTHON

    # Wrong - parsed JSON
    payload = json.dumps(request.json)

    # Correct - raw body
    payload = request.get_data(as_text=True)

‍

  1. Encoding issues: Ensure UTF-8
  2. Wrong secret: Verify the secret from the dashboard

‍

Problem: Duplicate Webhook Events

Cause: Webhook retry on non-200 response

‍

Resolution:

PYTHON

# Implement idempotency
processed_events = set()

def handle_webhook(event):
    event_id = event.get('id')

    if event_id in processed_events:
        return  # Already processed

    processed_events.add(event_id)
    # Process event...

‍

Best Practice: Store event IDs in the database:

‍

SQL

CREATE TABLE webhook_events (
    event_id VARCHAR(50) PRIMARY KEY,
    event_type VARCHAR(50),
    processed_at TIMESTAMP DEFAULT NOW()
);

‍

Recurring Payment Issues

Problem: Token Not Created

Symptoms:

  • force_recurring: true set but no token
  • Empty token list for client

‍

Causes:

  • Payment not completed
  • The payment amount was 0 without skip_capture
  • Token creation is disabled for the payment method

‍

Debug:

BASH

# Check if payment completed
GET /purchases/{id}/

# Verify status is "paid" or "hold"

# List client tokens
GET /clients/{client_id}/recurring_tokens/

‍

Resolution:

For zero-amount tokenization:

‍

JSON

{
  "purchase": {
    "products": [{"name": "Auth", "price": 0}]
  },
  "skip_capture": true,
  "force_recurring": true
}

‍

Problem: Token Charge Failed

Symptoms:

  • /charge/ endpoint returns error
  • Token exists, but won't charge

‍

Error Types:

ErrorCauseSolution
recurring_token_not_foundInvalid token IDVerify token exists
recurring_token_expiredCard expiredRe-tokenize
card_declinedInsufficient fundsContact customer

‍

Debug:

BASH

# Verify token exists
GET /clients/{client_id}/recurring_tokens/{token_id}/

# Check original purchase
GET /purchases/{token_id}/

‍

Direct Post Issues

Problem: direct_post_url is null

Causes:

  • Missing redirect URLs
  • purchase.request_client_details not empty
  • Purchase not in created state

‍

Resolution:

JSON

{
  "success_redirect": "https://...",  // Required
  "failure_redirect": "https://...",  // Required
  "purchase": {
    "request_client_details": []  // Must be empty
  }
}

‍

Problem: Direct Post Returns to Failure

Symptoms:

  • Valid card details
  • Redirect to failure URL

‍

Debug Checklist:

  • Form fields match expected names exactly
  • Card number has no spaces
  • Expiry format is MM/YY
  • CVC is 3-4 digits
  • Cardholder name uses Latin characters only

‍

Field Requirements:

HTML

<!-- Exact field names required -->
<input name='cardholder_name'>  <!-- Latin, max 30 chars -->
<input name='card_number'>       <!-- Digits only, max 19 -->
<input name='expires'>           <!-- MM/YY format -->
<input name='cvc'>               <!-- 3-4 digits -->
<input name='pm' value='visa'>   <!-- Payment method -->

‍

Performance Issues

Problem: Slow API Responses

Diagnosis:

PYTHON

import time

start = time.time()
response = requests.get(url, headers=headers)
elapsed = time.time() - start
print(f"Response time: {elapsed:.2f}s")

‍

Causes:

  • Network latency
  • Large response payloads
  • Server load

‍

Resolution:

  1. Implement connection pooling
  2. Use pagination for list endpoints
  3. Cache responses where appropriate
  4. Implement timeout handling

‍

Problem: Rate Limit Exceeded

Symptoms:

JSON

HTTP 429 Too Many Requests

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

‍

Resolution:

PYTHON

import time

def api_request_with_backoff(func, max_retries=3):
    for attempt in range(max_retries):
        response = func()

        if response.status_code == 429:
            reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
            wait = max(reset_time - time.time(), 2 ** attempt)
            print(f"Rate limited. Waiting {wait:.0f}s...")
            time.sleep(wait)
            continue

        return response

    raise Exception("Rate limit exceeded after retries")

‍

Debugging Tools

Request Logging

PYTHON

import logging

logging.basicConfig(level=logging.DEBUG)

# Log all requests
import http.client
http.client.HTTPConnection.debuglevel = 1

‍

Response Inspection

PYTHON

def debug_response(response):
    print(f"Status: {response.status_code}")
    print(f"Headers: {dict(response.headers)}")
    print(f"Body: {response.text}")

‍

cURL Verbose Mode

BASH

curl -v -X POST "https://gate.reviopay.com/api/v1/purchases/" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"..."}'

‍

Error Message Reference

ErrorHTTPQuick Fix
invalid_token401Check API key format
required400Add missing field
does_not_exist404Verify UUID
duplicate_client409Search existing client
purchase_already_paid409Check status first
recurring_token_expired409Re-tokenize card
rate_limit_exceeded429Implement backoff

‍

Getting Support

Before Contacting Support

  1. Collect information:
  • Request ID (if available)
  • Full error response
  • Request payload (sanitized)
  • Timestamp of issue
  1. Check dashboard:
  • Transaction history
  • Webhook logs
  • Event logs
  1. Review documentation:
  • API reference
  • Error codes guide

‍

Contact Support

Email: support@precium.com

‍

Include:

  • Merchant ID / Brand ID
  • Environment (Sandbox/Production)
  • Purchase ID(s) affected
  • Steps to reproduce
  • Error messages
  • Timestamps