Via.One API - Integration Quick Start Guide¶
Get up and running with Via.One in 15 minutes
Table of Contents¶
- Prerequisites
- Step 1: Get Your Credentials
- Step 2: Install Dependencies
- Step 3: Test Authentication
- Step 4: Process Your First Topup
- Step 5: Check Transaction Status
- Step 6: Go to Production
- Common Integration Patterns
- Troubleshooting
Prerequisites¶
- Active Via.One account
- API credentials (contact support@relier.group)
- Development environment (Node.js 14+, Python 3.7+, or PHP 7.4+)
- HTTPS support for webhooks (optional)
Step 1: Get Your Credentials¶
Test Credentials (For Development)¶
API_KEY: test_viaone_key_cellpay_sandbox
CUSTOMER_ID: cellpay_test_001
BASE_URL: https://latcom-fix-production.up.railway.app
Production Credentials¶
Contact Via.One to receive production credentials:
- Email: support@relier.group
- Phone: +1 (704) 649-0570
You will receive:
- Production API_KEY
- Production CUSTOMER_ID
- Webhook secret (if using webhooks)
Step 2: Install Dependencies¶
Node.js¶
Python¶
PHP¶
Step 3: Test Authentication¶
Node.js Example¶
Create a file test-viaone.js:
const axios = require('axios');
const VIA_ONE_API_KEY = 'test_viaone_key_cellpay_sandbox';
const VIA_ONE_CUSTOMER_ID = 'cellpay_test_001';
const VIA_ONE_BASE_URL = 'https://latcom-fix-production.up.railway.app';
async function testAuth() {
try {
const response = await axios.get(
`${VIA_ONE_BASE_URL}/api/v1/balance`,
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
}
);
console.log('✅ Authentication successful!');
console.log('Balance:', response.data);
return true;
} catch (error) {
console.error('❌ Authentication failed:', error.response?.data || error.message);
return false;
}
}
testAuth();
Run it:
Expected Output:
✅ Authentication successful!
Balance: {
success: true,
customer_id: 'cellpay_test_001',
balance: 100000.00,
currency: 'MXN'
}
Step 4: Process Your First Topup¶
Node.js Example¶
const axios = require('axios');
const VIA_ONE_API_KEY = 'test_viaone_key_cellpay_sandbox';
const VIA_ONE_CUSTOMER_ID = 'cellpay_test_001';
const VIA_ONE_BASE_URL = 'https://latcom-fix-production.up.railway.app';
async function processTopup() {
try {
const response = await axios.post(
`${VIA_ONE_BASE_URL}/api/v1/topup`,
{
carrier: 'MOVISTAR',
phone: '5512345678',
amount: 50,
reference: `TEST-${Date.now()}`
},
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
}
);
console.log('✅ Topup successful!');
console.log('Transaction ID:', response.data.transaction_id);
console.log('Authorization:', response.data.authorization_code);
console.log('Full response:', JSON.stringify(response.data, null, 2));
return response.data;
} catch (error) {
console.error('❌ Topup failed:', error.response?.data || error.message);
return null;
}
}
processTopup();
Python Example¶
import requests
import time
VIA_ONE_API_KEY = 'test_viaone_key_cellpay_sandbox'
VIA_ONE_CUSTOMER_ID = 'cellpay_test_001'
VIA_ONE_BASE_URL = 'https://latcom-fix-production.up.railway.app'
def process_topup():
url = f'{VIA_ONE_BASE_URL}/api/v1/topup'
headers = {
'Authorization': f'Bearer {VIA_ONE_API_KEY}',
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
data = {
'carrier': 'MOVISTAR',
'phone': '5512345678',
'amount': 50,
'reference': f'TEST-{int(time.time())}'
}
response = requests.post(url, json=data, headers=headers)
if response.status_code == 200:
print('✅ Topup successful!')
result = response.json()
print(f"Transaction ID: {result['transaction_id']}")
print(f"Authorization: {result['authorization_code']}")
return result
else:
print('❌ Topup failed:', response.json())
return None
process_topup()
PHP Example¶
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$VIA_ONE_API_KEY = 'test_viaone_key_cellpay_sandbox';
$VIA_ONE_CUSTOMER_ID = 'cellpay_test_001';
$VIA_ONE_BASE_URL = 'https://latcom-fix-production.up.railway.app';
function processTopup() {
global $VIA_ONE_API_KEY, $VIA_ONE_CUSTOMER_ID, $VIA_ONE_BASE_URL;
$client = new Client();
try {
$response = $client->post($VIA_ONE_BASE_URL . '/api/v1/topup', [
'headers' => [
'Authorization' => 'Bearer ' . $VIA_ONE_API_KEY,
'X-Customer-ID' => $VIA_ONE_CUSTOMER_ID,
'Content-Type' => 'application/json'
],
'json' => [
'carrier' => 'MOVISTAR',
'phone' => '5512345678',
'amount' => 50,
'reference' => 'TEST-' . time()
]
]);
$result = json_decode($response->getBody(), true);
echo "✅ Topup successful!\n";
echo "Transaction ID: " . $result['transaction_id'] . "\n";
echo "Authorization: " . $result['authorization_code'] . "\n";
return $result;
} catch (Exception $e) {
echo "❌ Topup failed: " . $e->getMessage() . "\n";
return null;
}
}
processTopup();
?>
Expected Output:
Step 5: Check Transaction Status¶
async function checkStatus(transactionId) {
try {
const response = await axios.get(
`${VIA_ONE_BASE_URL}/api/v1/transaction/${transactionId}`,
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID
}
}
);
console.log('Transaction Status:', response.data.status);
console.log('Full details:', JSON.stringify(response.data, null, 2));
return response.data;
} catch (error) {
console.error('Status check failed:', error.response?.data || error.message);
return null;
}
}
// Usage
checkStatus('VIA-20251108-001234');
Step 6: Go to Production¶
Checklist¶
- Test all transaction types in test environment
- Implement error handling for all API calls
- Set up logging for transaction IDs and responses
- Configure webhooks (optional but recommended)
- Implement retry logic for network errors
- Request production credentials from Via.One
- Update API keys in production environment
- Test with small amounts before full rollout
- Set up monitoring and alerts
- Document your integration for your team
Production Configuration¶
// config/production.js
module.exports = {
viaone: {
apiKey: process.env.VIA_ONE_API_KEY,
customerId: process.env.VIA_ONE_CUSTOMER_ID,
baseUrl: 'https://latcom-fix-production.up.railway.app',
timeout: 60000, // 60 seconds
maxRetries: 3
}
};
Environment Variables¶
# .env.production
VIA_ONE_API_KEY=prod_viaone_key_YOUR_KEY_HERE
VIA_ONE_CUSTOMER_ID=cellpay_prod_001
VIA_ONE_WEBHOOK_SECRET=your_webhook_secret_here
Common Integration Patterns¶
Pattern 1: Topup with Retry Logic¶
async function topupWithRetry(phone, amount, carrier, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await axios.post(
`${VIA_ONE_BASE_URL}/api/v1/topup`,
{
carrier,
phone,
amount,
reference: `ORDER-${Date.now()}-${attempt}`
},
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
},
timeout: 60000 // 60 seconds
}
);
return {
success: true,
data: response.data
};
} catch (error) {
const status = error.response?.status;
// Don't retry on 4xx errors (except 429 rate limit)
if (status >= 400 && status < 500 && status !== 429) {
return {
success: false,
error: error.response.data,
retryable: false
};
}
// Last attempt failed
if (attempt === maxRetries) {
return {
success: false,
error: error.response?.data || { message: error.message },
retryable: true
};
}
// Wait before retrying (exponential backoff)
const delay = Math.pow(2, attempt - 1) * 1000;
console.log(`Retry attempt ${attempt} after ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
const result = await topupWithRetry('5512345678', 50, 'MOVISTAR');
if (result.success) {
console.log('Topup successful:', result.data.transaction_id);
} else {
console.error('Topup failed:', result.error);
}
Pattern 2: Batch Processing¶
async function processBatchTopups(topups) {
const results = [];
const batchSize = 5; // Process 5 at a time
for (let i = 0; i < topups.length; i += batchSize) {
const batch = topups.slice(i, i + batchSize);
const promises = batch.map(topup => processTopup(topup));
const batchResults = await Promise.allSettled(promises);
results.push(...batchResults);
// Wait 1 second between batches to avoid rate limiting
if (i + batchSize < topups.length) {
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return results;
}
async function processTopup(topup) {
const response = await axios.post(
`${VIA_ONE_BASE_URL}/api/v1/topup`,
{
carrier: topup.carrier,
phone: topup.phone,
amount: topup.amount,
reference: topup.reference
},
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
}
);
return response.data;
}
Pattern 3: Bill Payment with Validation¶
async function payBill(companyCode, referenceNumber, amount) {
// Step 1: Validate company code
const companies = await getCompanies();
const company = companies.find(c => c.code === companyCode);
if (!company) {
return {
success: false,
error: `Invalid company code: ${companyCode}`
};
}
// Step 2: Validate amount
if (amount < company.min_amount || amount > company.max_amount) {
return {
success: false,
error: `Amount must be between ${company.min_amount} and ${company.max_amount}`
};
}
// Step 3: Process payment
try {
const response = await axios.post(
`${VIA_ONE_BASE_URL}/api/v1/bill-payment`,
{
company_code: companyCode,
reference_number: referenceNumber,
amount: amount,
customer_reference: `BILL-${Date.now()}`
},
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
}
);
return {
success: true,
data: response.data
};
} catch (error) {
return {
success: false,
error: error.response?.data || { message: error.message }
};
}
}
async function getCompanies() {
const response = await axios.get(
`${VIA_ONE_BASE_URL}/api/v1/bill-payment/companies`,
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID
}
}
);
return response.data.companies;
}
Pattern 4: SPEI Transfer with Validation¶
async function createSpeiTransfer(transfer) {
// Validate CLABE (18 digits)
if (!/^\d{18}$/.test(transfer.clabe)) {
return {
success: false,
error: 'CLABE must be 18 digits'
};
}
// Validate amount
if (transfer.amount < 1 || transfer.amount > 1000000) {
return {
success: false,
error: 'Amount must be between 1 and 1,000,000 MXN'
};
}
try {
const response = await axios.post(
`${VIA_ONE_BASE_URL}/api/v1/spei`,
{
amount: transfer.amount,
recipient_name: transfer.recipientName,
recipient_bank: transfer.bankCode,
recipient_account: transfer.accountNumber,
recipient_clabe: transfer.clabe,
reference: transfer.description,
customer_reference: `SPEI-${Date.now()}`
},
{
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
}
);
return {
success: true,
data: response.data
};
} catch (error) {
return {
success: false,
error: error.response?.data || { message: error.message }
};
}
}
Troubleshooting¶
Common Issues¶
Issue: "401 Unauthorized"¶
Cause: Invalid or missing credentials
Solution:
// Check that credentials are correct
console.log('API Key:', VIA_ONE_API_KEY.substring(0, 10) + '...');
console.log('Customer ID:', VIA_ONE_CUSTOMER_ID);
// Ensure headers are included in every request
headers: {
'Authorization': `Bearer ${VIA_ONE_API_KEY}`,
'X-Customer-ID': VIA_ONE_CUSTOMER_ID,
'Content-Type': 'application/json'
}
Issue: "403 Insufficient Balance"¶
Cause: Account balance too low
Solution:
// Check your balance first
const balance = await axios.get(`${VIA_ONE_BASE_URL}/api/v1/balance`, {
headers: { /* ... */ }
});
console.log('Current balance:', balance.data.balance);
// Contact support to add funds: support@relier.group
Issue: "Timeout" or "ETIMEDOUT"¶
Cause: Request taking too long
Solution:
// Increase timeout to 60 seconds
const response = await axios.post(url, data, {
headers: { /* ... */ },
timeout: 60000 // 60 seconds
});
Issue: "429 Rate Limit Exceeded"¶
Cause: Too many requests
Solution:
// Implement rate limiting
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
// Wait between requests
for (const item of items) {
await processItem(item);
await delay(200); // 200ms delay between requests
}
Issue: Transaction shows "pending" for too long¶
Cause: Provider delay or timeout
Solution:
// Poll for status updates
async function waitForCompletion(transactionId, maxWait = 120000) {
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
const status = await checkStatus(transactionId);
if (status.status === 'completed') {
return { success: true, data: status };
}
if (status.status === 'failed') {
return { success: false, error: 'Transaction failed' };
}
// Wait 5 seconds before checking again
await new Promise(resolve => setTimeout(resolve, 5000));
}
return { success: false, error: 'Timeout waiting for completion' };
}
Next Steps¶
- Read the full API documentation:
VIA_ONE_API_v1.0.md - Test all services you plan to use
- Set up error logging and monitoring
- Configure webhooks for payment notifications
- Request production credentials when ready
- Launch in production with confidence!
Support¶
Need help?
- Email: support@relier.group
- Phone: +1 (704) 649-0570
- Hours: Monday - Friday, 9:00 AM - 6:00 PM EST
Happy Integrating! 🚀
Via.One - Powering payment services across Mexico