Skip to content

Via.One API - Integration Quick Start Guide

Get up and running with Via.One in 15 minutes


Table of Contents

  1. Prerequisites
  2. Step 1: Get Your Credentials
  3. Step 2: Install Dependencies
  4. Step 3: Test Authentication
  5. Step 4: Process Your First Topup
  6. Step 5: Check Transaction Status
  7. Step 6: Go to Production
  8. Common Integration Patterns
  9. 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

npm install axios

Python

pip install requests

PHP

composer require guzzlehttp/guzzle

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:

node test-viaone.js

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:

✅ Topup successful!
Transaction ID: VIA-20251108-001234
Authorization: AUTH-789456

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

  1. Read the full API documentation: VIA_ONE_API_v1.0.md
  2. Test all services you plan to use
  3. Set up error logging and monitoring
  4. Configure webhooks for payment notifications
  5. Request production credentials when ready
  6. 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