Chiron Payment Integration Guide

This guide will walk you through the process of integrating Chiron Payments into your application. The integration involves both backend and frontend components working together to process payments securely.

Note: This guide assumes you have already signed up for a Chiron Payments account and have your API credentials.

Integration Overview

The Chiron payment flow consists of two main parts:

  1. Backend Integration: Generate a transaction token for the payment amount
  2. Frontend Integration: Collect payment details and process the payment using the token
Important: Never process payment tokens directly from the frontend for security reasons. The token generation should always happen on your server.

Step 1: Backend Integration

The first step is to generate a transaction token from your backend server. This token authorizes a payment of a specific amount.

Generate a Transaction Token

// Using Node.js with Express
const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

app.post('/create-payment-token', async (req, res) => {
  try {
    // Get the amount from the request
    const { amount } = req.body;
    
    // Generate a unique ID for this transaction
    
    // Call Chiron API to get a token
    const response = await axios.post('https://api.chironapp.io/api/transactions/token/generate', {
      amount: amount,
    }, {
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer YOUR_API_KEY'
      }
    });
    
    // Return the token to your frontend
    res.json({ 
      token: response.data.id,
      amount: amount
    });
  } catch (error) {
    console.error('Error generating token:', error);
    res.status(500).json({ error: 'Failed to generate payment token' });
  }
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});
# Using Python with Flask
from flask import Flask, request, jsonify
import requests
import time

app = Flask(__name__)

@app.route('/create-payment-token', methods=['POST'])
def create_payment_token():
    try:
        // Get the amount from the request
        data = request.get_json()
        amount = data.get('amount')
        
        // Generate a unique ID for this transaction
        transaction_id = str(int(time.time()))
        
        // Call Chiron API to get a token
        response = requests.post(
            'https://api.chironapp.io/api/transactions/token/generate',
            json={
                'amount': amount
            },
            headers={
                'Content-Type': 'application/json',
                'Authorization': 'Bearer YOUR_API_KEY'
            }
        )
        
        response_data = response.json()
        
        // Return the token to your frontend
        return jsonify({
            'token': response_data['id'],
            'amount': amount
        })
    except Exception as e:
        print(f'Error generating token: {str(e)}')
        return jsonify({'error': 'Failed to generate payment token'}), 500

if __name__ == '__main__':
    app.run(debug=True, port=3000)
<?php
// Using PHP
header('Content-Type: application/json');

$data = json_decode(file_get_contents('php://input'), true);
$amount = $data['amount'] ?? null;

if (!$amount) {
    http_response_code(400);
    echo json_encode(['error' => 'Amount is required']);
    exit;
}

// Generate a unique ID for this transaction

// Call Chiron API to get a token
$ch = curl_init('https://api.chironapp.io/api/transactions/token/generate');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'amount' => $amount
]));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Authorization: Bearer YOUR_API_KEY'
]);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($httpCode !== 200) {
    http_response_code(500);
    echo json_encode(['error' => 'Failed to generate payment token']);
    exit;
}

$responseData = json_decode($response, true);

// Return the token to your frontend
echo json_encode([
    'token' => $responseData['id'],
    'amount' => $amount
]);
?>

Step 2: Frontend Integration

Once you have the token from your backend, you can use it in your frontend to process the payment.

1. Include the Chiron Checkout Script

<!-- Add this to your HTML head section -->
<script src="https://payment.chironapp.io/chiron-checkout.js"></script>

2. Create a Payment Form

<form id="payment-form">
    <div class="form-group">
        <label for="card-name">Cardholder Name</label>
        <input type="text" id="card-name" placeholder="John Smith" required>
    </div>
    
    <div class="form-group">
        <label for="card-number">Card Number</label>
        <input type="text" id="card-number" placeholder="4242 4242 4242 4242" required>
    </div>
    
    <div class="row">
        <div class="col">
            <div class="form-group">
                <label for="expiry">Expiration Date</label>
                <input type="text" id="expiry" placeholder="MM/YY" required>
            </div>
        </div>
        <div class="col">
            <div class="form-group">
                <label for="cvc">CVC</label>
                <input type="text" id="cvc" placeholder="123" required maxlength="4">
            </div>
        </div>
    </div>
    
    <!-- Billing Address Fields -->
    <div class="form-group">
        <label for="address">Street Address</label>
        <input type="text" id="address" placeholder="123 Main St" required>
    </div>
    
    <div class="row">
        <div class="col">
            <div class="form-group">
                <label for="city">City</label>
                <input type="text" id="city" placeholder="San Francisco" required>
            </div>
        </div>
        <div class="col">
            <div class="form-group">
                <label for="state">State</label>
                <input type="text" id="state" placeholder="CA" required>
            </div>
        </div>
    </div>
    
    <div class="form-group">
        <label for="zip">ZIP Code</label>
        <input type="text" id="zip" placeholder="94103" required>
    </div>
    
    <button type="submit">Pay Now</button>
    
    <div id="payment-message" class="error" style="display: none;"></div>
    <div id="success-message" class="success" style="display: none;"></div>
</form>

3. Handle the Payment Submission

document.addEventListener('DOMContentLoaded', function() {
    const form = document.getElementById('payment-form');
    const paymentMessage = document.getElementById('payment-message');
    const successMessage = document.getElementById('success-message');
    
    // Format card number with spaces
    const cardNumberInput = document.getElementById('card-number');
    cardNumberInput.addEventListener('input', function(e) {
        let value = e.target.value.replace(/\s+/g, '');
        if (value.length > 0) {
            value = value.match(new RegExp('.{1,4}', 'g')).join(' ');
        }
        e.target.value = value;
    });
    
    // Format expiry date
    const expiryInput = document.getElementById('expiry');
    expiryInput.addEventListener('input', function(e) {
        let value = e.target.value.replace(/\D/g, '');
        if (value.length > 2) {
            value = value.substring(0, 2) + '/' + value.substring(2, 4);
        }
        e.target.value = value;
    });
    
    form.addEventListener('submit', async function(e) {
        e.preventDefault();
        
        // Hide any previous messages
        paymentMessage.style.display = 'none';
        successMessage.style.display = 'none';
        
        // Get form values
        const name = document.getElementById('card-name').value;
        const cardNumber = document.getElementById('card-number').value.replace(/\s+/g, '');
        const expiry = document.getElementById('expiry').value.replace('/', '');
        const cvc = document.getElementById('cvc').value;
        const address = document.getElementById('address').value;
        const city = document.getElementById('city').value;
        const state = document.getElementById('state').value;
        const zip = document.getElementById('zip').value;
        
        // Validate form
        if (!validateForm()) {
            return;
        }
        
        try {
            // First, get a payment token from your backend
            const tokenResponse = await fetch('/create-payment-token', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    amount: 1.00 // Replace with your actual amount
                })
            });
            
            const tokenData = await tokenResponse.json();
            
            if (!tokenData.token) {
                throw new Error('Failed to generate payment token');
            }
            
            // Define callback
            const callback = {
                onError: (error) => {
                    paymentMessage.textContent = error.ssl_result_message || 'An error occurred during payment processing.';
                    paymentMessage.style.display = 'block';
                },
                onDeclined: async (error) => {
                    console.error(error);
                    paymentMessage.textContent = error.errorMessage || 'Payment was declined.';
                    paymentMessage.style.display = 'block';
                },
                onApproval: async (response) => {
                    try {
                        successMessage.textContent = 'Payment succeeded.';
                        successMessage.style.display = 'block';
                        form.reset();
                    } catch (err) {
                        paymentMessage.textContent = err.error || 'An error occurred after approval.';
                        paymentMessage.style.display = 'block';
                    }
                }
            };
            
            // Process payment using ChironPayment.pay() - see detailed explanation below
            window.ChironPayment.pay(
                {
                    ssl_amount: tokenData.amount.toString(),
                    ssl_transaction_type: 'ccsale',
                    ssl_txn_auth_token: tokenData.token,
                    ssl_exp_date: expiry,
                    ssl_cvv2cvc2: cvc,
                    ssl_card_number: cardNumber,
                    ssl_get_token: 'Y',
                    ssl_add_token: 'Y',
                    ssl_first_name: name.split(' ')[0],
                    ssl_last_name: name.split(' ')[1] || '',
                    ssl_avs_zip: zip,
                    ssl_city: city,
                    ssl_state: state,
                    ssl_avs_address: address,
                },
                callback
            );
        } catch (error) {
            paymentMessage.textContent = 'Failed to initialize payment: ' + (error.message || 'Unknown error');
            paymentMessage.style.display = 'block';
        }
    });
    
    function validateForm() {
        // Basic validation
        const cardNumber = document.getElementById('card-number').value.replace(/\s+/g, '');
        if (cardNumber.length < 13 || cardNumber.length > 19) {
            paymentMessage.textContent = 'Please enter a valid card number.';
            paymentMessage.style.display = 'block';
            return false;
        }
        
        const expiry = document.getElementById('expiry').value;
        if (!expiry.match(/^\d{2}\/\d{2}$/)) {
            paymentMessage.textContent = 'Please enter a valid expiration date (MM/YY).';
            paymentMessage.style.display = 'block';
            return false;
        }
        
        const cvc = document.getElementById('cvc').value;
        if (cvc.length < 3 || cvc.length > 4) {
            paymentMessage.textContent = 'Please enter a valid CVC code.';
            paymentMessage.style.display = 'block';
            return false;
        }
        
        return true;
    }
});

4. Understanding ChironPayment.pay() Method

The core of the payment processing is handled by the ChironPayment.pay() method. This method takes two parameters: a payment configuration object and a callback object.

Payment Configuration Object

The payment configuration object contains all the necessary details for processing the payment:

window.ChironPayment.pay(
    {
        // Payment amount from the token response
        ssl_amount: tokenData.amount.toString(),
        
        // Transaction type - 'ccsale' for credit card sale
        ssl_transaction_type: 'ccsale',
        
        // The token received from your backend
        ssl_txn_auth_token: tokenData.token,
        
        // Card details
        ssl_exp_date: expiry,         // Format: MMYY (no slash)
        ssl_cvv2cvc2: cvc,            // Security code
        ssl_card_number: cardNumber,  // Card number (no spaces)
        
        // Token options
        ssl_get_token: 'Y',           // Get a token for this card
        ssl_add_token: 'Y',           // Add the token to the customer's saved cards
        
        // Cardholder information
        ssl_first_name: name.split(' ')[0],
        ssl_last_name: name.split(' ')[1] || '',
        
        // Billing address for AVS verification
        ssl_avs_zip: zip,
        ssl_city: city,
        ssl_state: state,
        ssl_avs_address: address,
    },
    callback
);
Parameter Details:
  • ssl_amount: The payment amount as a string (e.g., "10.99")
  • ssl_transaction_type: Type of transaction, usually "ccsale" for credit card sales
  • ssl_txn_auth_token: The token generated by your backend
  • ssl_exp_date: Card expiration date in MMYY format (no slash)
  • ssl_cvv2cvc2: Card verification code (CVC/CVV)
  • ssl_card_number: Credit card number with no spaces
  • ssl_get_token: Set to "Y" to tokenize the card for future use
  • ssl_add_token: Set to "Y" to save the token to the customer's profile
  • ssl_first_name & ssl_last_name: Cardholder's name
  • ssl_avs_zip, ssl_city, ssl_state, ssl_avs_address: Billing address for AVS (Address Verification System) checks

Callback Object

The callback object defines how your application will handle different payment outcomes:

const callback = {
    // Called when a system error occurs
    onError: (error) => {
        paymentMessage.textContent = error.ssl_result_message || 'An error occurred during payment processing.';
        paymentMessage.style.display = 'block';
    },
    
    // Called when the payment is declined
    onDeclined: async (error) => {
        console.error(error);
        paymentMessage.textContent = error.errorMessage || 'Payment was declined.';
        paymentMessage.style.display = 'block';
    },
    
    // Called when the payment is approved
    onApproval: async (response) => {
        try {
            successMessage.textContent = 'Payment succeeded.';
            successMessage.style.display = 'block';
            form.reset();
            
            // You might want to redirect to a success page or perform other actions
            // such as updating order status in your database
        } catch (err) {
            paymentMessage.textContent = err.error || 'An error occurred after approval.';
            paymentMessage.style.display = 'block';
        }
    }
};
Important: Always implement proper error handling in all callback functions to provide a good user experience when issues occur.

Additional Configuration Options

The payment configuration object supports additional parameters for more advanced use cases:

Best Practice: Include as much customer information as possible to improve fraud detection and reduce the likelihood of chargebacks.

Testing Your Integration

You can test your integration using the following test card details:

Success Response: When a payment is successful, the onApproval callback will be triggered.

Going to Production

Before going live with your integration, make sure to:

  1. Switch to your production API keys
  2. Implement proper error handling and logging
  3. Set up webhooks for payment notifications (recommended)
  4. Implement security best practices like HTTPS and CSRF protection
Support: If you encounter any issues with your integration, please contact Chiron support at [email protected].