Integration Examples
This section provides complete code examples for the most common use cases, using different technologies and programming languages.
π Example 1: Authentication and First Queryβ
JavaScript/Node.jsβ
const axios = require('axios');
class MaxCapitalClient {
constructor(baseURL, clientId, clientSecret) {
this.baseURL = baseURL;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.accessToken = null;
}
async authenticate() {
try {
const response = await axios.post(`${this.baseURL}/auth/api/v1/auth/login`, {
clientId: this.clientId,
clientSecret: this.clientSecret
});
this.accessToken = response.data.accessToken;
console.log('Authentication successful');
return response.data;
} catch (error) {
console.error('Authentication error:', error.response?.data);
throw error;
}
}
async getMutualFund(cafciCode) {
if (!this.accessToken) {
await this.authenticate();
}
try {
const response = await axios.get(
`${this.baseURL}/mutual-funds/api/v1/mutual-funds/${cafciCode}`,
{
headers: {
'Authorization': `Bearer ${this.accessToken}`
}
}
);
return response.data;
} catch (error) {
console.error('Error querying fund:', error.response?.data);
throw error;
}
}
}
// Client usage
const client = new MaxCapitalClient(
'https://api-dev.max.capital',
'demo-client-dev',
'your-client-secret'
);
// Query fund information
client.getMutualFund('3852').then(fund => {
console.log(`Fund: ${fund.name}`);
console.log(`Price: $${fund.price}`);
console.log(`Variation: ${fund.variation}%`);
});
Pythonβ
import requests
from datetime import datetime, timedelta
class MaxCapitalAPI:
def __init__(self, base_url, client_id, client_secret):
self.base_url = base_url
self.client_id = client_id
self.client_secret = client_secret
self.access_token = None
self.token_expires_at = None
def authenticate(self):
"""Get access token"""
auth_url = f"{self.base_url}/auth/api/v1/auth/login"
payload = {
"clientId": self.client_id,
"clientSecret": self.client_secret
}
response = requests.post(auth_url, json=payload)
response.raise_for_status()
data = response.json()
self.access_token = data['accessToken']
# Calculate expiration (expires_in is in minutes)
self.token_expires_at = datetime.now() + timedelta(minutes=data['expiresIn'])
return data
def _get_headers(self):
"""Verify token and return headers"""
if not self.access_token or datetime.now() >= self.token_expires_at:
self.authenticate()
return {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json"
}
def get_mutual_fund_holdings(self, account_number, date=None, fund_code=None):
"""Query fund holdings"""
url = f"{self.base_url}/mutual-funds/api/v1/mutual-funds-holdings"
params = {
"accountHolderNumber": account_number,
"Date": date or datetime.now().strftime("%Y-%m-%d")
}
if fund_code:
params["mutualFundCafciCode"] = fund_code
response = requests.get(url, params=params, headers=self._get_headers())
response.raise_for_status()
return response.json()
# Usage example
api = MaxCapitalAPI(
"https://api-dev.max.capital",
"demo-client-dev",
"your-client-secret"
)
# Query holdings
holdings = api.get_mutual_fund_holdings(
account_number="11772",
date="2024-06-01"
)
print(f"Total valuation: ${holdings['valuation']:,.2f}")
print(f"Available shares: {holdings['availableShareAmounts']:,.4f}")
π° Example 2: Complete Subscription Flowβ
C# (.NET)β
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
public class MaxCapitalClient
{
private readonly HttpClient _httpClient;
private readonly string _baseUrl;
private readonly string _clientId;
private readonly string _clientSecret;
private string _accessToken;
private DateTime _tokenExpiresAt;
public MaxCapitalClient(string baseUrl, string clientId, string clientSecret)
{
_httpClient = new HttpClient();
_baseUrl = baseUrl;
_clientId = clientId;
_clientSecret = clientSecret;
}
public async Task<AuthResponse> AuthenticateAsync()
{
var authRequest = new
{
clientId = _clientId,
clientSecret = _clientSecret
};
var json = JsonSerializer.Serialize(authRequest);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"{_baseUrl}/auth/api/v1/auth/login", content);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
var authResponse = JsonSerializer.Deserialize<AuthResponse>(responseJson);
_accessToken = authResponse.AccessToken;
_tokenExpiresAt = DateTime.Now.AddMinutes(authResponse.ExpiresIn);
return authResponse;
}
private async Task EnsureAuthenticatedAsync()
{
if (string.IsNullOrEmpty(_accessToken) || DateTime.Now >= _tokenExpiresAt)
{
await AuthenticateAsync();
}
}
public async Task<SubscriptionResponse> CreateSubscriptionAsync(SubscriptionRequest request)
{
await EnsureAuthenticatedAsync();
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_accessToken}");
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(
$"{_baseUrl}/mutual-funds/api/v1/subscriptions",
content
);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<SubscriptionResponse>(responseJson);
}
public async Task<SubscriptionStatus> GetSubscriptionStatusAsync(int subscriptionId)
{
await EnsureAuthenticatedAsync();
_httpClient.DefaultRequestHeaders.Clear();
_httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {_accessToken}");
var response = await _httpClient.GetAsync(
$"{_baseUrl}/mutual-funds/api/v1/subscriptions/{subscriptionId}"
);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<SubscriptionStatus>(responseJson);
}
}
// DTOs
public class AuthResponse
{
public string AccessToken { get; set; }
public int ExpiresIn { get; set; }
public string TokenType { get; set; }
}
public class SubscriptionRequest
{
public int MutualFundCafciCode { get; set; }
public string CurrencyIsoCode { get; set; }
public string AccountHolderNumber { get; set; }
public decimal Amount { get; set; }
public string Cvu { get; set; }
}
public class SubscriptionResponse
{
public int Id { get; set; }
public string Status { get; set; }
public DateTime OperationDate { get; set; }
}
// Usage example
var client = new MaxCapitalClient(
"https://api-dev.max.capital",
"demo-client-dev",
"your-client-secret"
);
var subscriptionRequest = new SubscriptionRequest
{
MutualFundCafciCode = 3852,
CurrencyIsoCode = "ARS",
AccountHolderNumber = "11772",
Amount = 10000m,
Cvu = "0000003100059118503787"
};
var subscription = await client.CreateSubscriptionAsync(subscriptionRequest);
Console.WriteLine($"Subscription created with ID: {subscription.Id}");
// Status polling
bool isCompleted = false;
while (!isCompleted)
{
await Task.Delay(5000); // Wait 5 seconds
var status = await client.GetSubscriptionStatusAsync(subscription.Id);
Console.WriteLine($"Current status: {status.Status}");
if (status.Status == "COMPLETED" || status.Status == "ERROR")
{
isCompleted = true;
}
}
π Example 3: Report Automationβ
PHPβ
<?php
class MaxCapitalReportGenerator
{
private $apiClient;
private $dbConnection;
public function __construct($apiClient, $dbConnection)
{
$this->apiClient = $apiClient;
$this->dbConnection = $dbConnection;
}
/**
* Generate daily operations report
*/
public function generateDailyReport($date = null)
{
$date = $date ?: date('Y-m-d');
// Get all company accounts
$accounts = $this->getCompanyAccounts();
$allOperations = [];
foreach ($accounts as $account) {
// Query day's subscriptions
$subscriptions = $this->apiClient->get('/v1/subscriptions', [
'operationDate' => $date,
'accountHolderNumber' => $account['number']
]);
// Query day's redemptions
$redemptions = $this->apiClient->get('/v1/redemptions', [
'operationDate' => $date,
'accountHolderNumber' => $account['number']
]);
$allOperations = array_merge($allOperations, $subscriptions, $redemptions);
}
// Generate report
$report = [
'date' => $date,
'total_subscriptions' => 0,
'total_redemptions' => 0,
'operations' => []
];
foreach ($allOperations as $operation) {
if (isset($operation['mutualFundCafciCode'])) { // It's a subscription
$report['total_subscriptions'] += $operation['amount'];
} else { // It's a redemption
$report['total_redemptions'] += $operation['amount'];
}
$report['operations'][] = [
'type' => isset($operation['mutualFundCafciCode']) ? 'SUBSCRIPTION' : 'REDEMPTION',
'id' => $operation['id'],
'account' => $operation['accountHolderNumber'],
'fund' => $operation['mutualFundCafciCode'] ?? $operation['mutualFundCafciCode'],
'amount' => $operation['amount'],
'status' => $operation['status'],
'operation_date' => $operation['operationDate']
];
}
// Save to database
$this->saveReportToDatabase($report);
// Generate Excel
$this->generateExcelReport($report);
return $report;
}
/**
* Sync positions with ERP
*/
public function syncPositionsWithERP()
{
$accounts = $this->getCompanyAccounts();
foreach ($accounts as $account) {
// Get current position
$holdings = $this->apiClient->get('/v1/mutual-funds-holdings', [
'Date' => date('Y-m-d'),
'accountHolderNumber' => $account['number']
]);
// Update in ERP
$this->updateERPPosition($account['number'], $holdings);
}
}
private function updateERPPosition($accountNumber, $holdings)
{
$sql = "UPDATE asset_valuations
SET current_value = ?,
shares = ?,
price_per_share = ?,
last_updated = NOW()
WHERE account_number = ? AND asset_type = 'MUTUAL_FUND'";
$stmt = $this->dbConnection->prepare($sql);
$stmt->execute([
$holdings['valuation'],
$holdings['availableShareAmounts'],
$holdings['sharePrice'],
$accountNumber
]);
}
private function generateExcelReport($report)
{
// Use PhpSpreadsheet to generate Excel
$spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
// Headers
$sheet->setCellValue('A1', 'Date');
$sheet->setCellValue('B1', 'Type');
$sheet->setCellValue('C1', 'Operation ID');
$sheet->setCellValue('D1', 'Account');
$sheet->setCellValue('E1', 'Fund');
$sheet->setCellValue('F1', 'Amount');
$sheet->setCellValue('G1', 'Status');
// Data
$row = 2;
foreach ($report['operations'] as $operation) {
$sheet->setCellValue("A{$row}", $operation['operation_date']);
$sheet->setCellValue("B{$row}", $operation['type']);
$sheet->setCellValue("C{$row}", $operation['id']);
$sheet->setCellValue("D{$row}", $operation['account']);
$sheet->setCellValue("E{$row}", $operation['fund']);
$sheet->setCellValue("F{$row}", $operation['amount']);
$sheet->setCellValue("G{$row}", $operation['status']);
$row++;
}
// Save file
$writer = new \PhpOffice\PhpSpreadsheet\Writer\Xlsx($spreadsheet);
$filename = "operations_report_{$report['date']}.xlsx";
$writer->save($filename);
return $filename;
}
}
// Configuration and usage
$config = [
'base_url' => 'https://api-dev.max.capital',
'client_id' => 'demo-client-dev',
'client_secret' => 'your-client-secret'
];
$apiClient = new MaxCapitalAPIClient($config);
$dbConnection = new PDO('mysql:host=localhost;dbname=company_erp', $username, $password);
$reportGenerator = new MaxCapitalReportGenerator($apiClient, $dbConnection);
// Generate daily report (run via cron)
$report = $reportGenerator->generateDailyReport();
echo "Report generated with {$report['total_operations']} operations\n";
// Sync positions (run every hour)
$reportGenerator->syncPositionsWithERP();
echo "Positions synced with ERP\n";
π Example 4: Current Account Movements Queryβ
Node.js - Automatic Download for ERPβ
const axios = require('axios');
class StatementsDownloader {
constructor(baseURL, clientId, clientSecret, companyConfig) {
this.baseURL = baseURL;
this.clientId = clientId;
this.clientSecret = clientSecret;
this.company = companyConfig;
this.accessToken = null;
}
async authenticate() {
try {
const response = await axios.post(`${this.baseURL}/auth/api/v1/auth/login`, {
clientId: this.clientId,
clientSecret: this.clientSecret
});
this.accessToken = response.data.accessToken;
return response.data;
} catch (error) {
console.error('Authentication error:', error.response?.data);
throw error;
}
}
async downloadDailyMovements(date) {
if (!this.accessToken) {
await this.authenticate();
}
try {
const response = await axios.get(
`${this.baseURL}/statements/api/v1/current-account/instruments`,
{
params: {
number: this.company.accountNumber,
dateFrom: date,
dateTo: date,
dateType: 'operation'
}
}
);
return response.data;
} catch (error) {
console.error('Error downloading movements:', error.response?.data);
throw error;
}
}
async processMovementsForERP(movements) {
const processedEntries = [];
movements.forEach(movement => {
// Determine accounting accounts according to instrument type
const accountMapping = this.getAccountMapping(movement.instrumentTypeCode, movement.amount);
const journalEntry = {
date: movement.settlementDate,
reference: movement.detail,
externalRef: `MC-${movement.currentAccountCode}-${movement.operationDate}`,
entries: [
{
account: accountMapping.debit,
debit: Math.abs(movement.net),
description: `${movement.instrumentDescription} - ${movement.detail}`
},
{
account: accountMapping.credit,
credit: Math.abs(movement.net),
description: `${movement.instrumentDescription} - ${movement.detail}`
}
]
};
processedEntries.push(journalEntry);
});
return processedEntries;
}
getAccountMapping(instrumentType, amount) {
// Specific mapping according to company's chart of accounts
const mappings = {
'FCI': {
debit: amount > 0 ? '1.1.3.001' : '1.1.1.001', // Mutual Fund Investments : Bank
credit: amount > 0 ? '1.1.1.001' : '1.1.3.001' // Bank : Mutual Fund Investments
},
'PLAZO_FIJO': {
debit: amount > 0 ? '1.1.2.001' : '1.1.1.001', // Fixed Deposits : Bank
credit: amount > 0 ? '1.1.1.001' : '1.1.2.001' // Bank : Fixed Deposits
},
'BONO': {
debit: amount > 0 ? '1.1.4.001' : '1.1.1.001', // Government Securities : Bank
credit: amount > 0 ? '1.1.1.001' : '1.1.4.001' // Bank : Government Securities
}
};
return mappings[instrumentType] || mappings['FCI'];
}
async runDailySync() {
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const dateStr = yesterday.toISOString().split('T')[0];
console.log(`Starting sync for date: ${dateStr}`);
try {
// 1. Download movements
const movements = await this.downloadDailyMovements(dateStr);
console.log(`Found ${movements.length} movements`);
// 2. Process for ERP
const journalEntries = await this.processMovementsForERP(movements);
// 3. Send to ERP (implement according to specific system)
for (const entry of journalEntries) {
await this.sendToERP(entry);
console.log(`Journal entry recorded: ${entry.reference}`);
}
console.log(`Sync completed: ${journalEntries.length} entries processed`);
} catch (error) {
console.error('Error in daily sync:', error);
throw error;
}
}
async sendToERP(journalEntry) {
// Generic example - adapt according to specific ERP
// SAP, Oracle, Tango, etc.
console.log('Sending to ERP:', journalEntry);
// Implement specific connection with company's ERP
// Example: REST API, CSV file, direct database, etc.
}
}
// Configuration and usage
const companyConfig = {
documentNumber: '30123456789', // Company CUIT
accountNumber: '12345678' // Max Capital account number
};
const downloader = new StatementsDownloader(
'https://api-dev.max.capital',
'demo-client-dev',
'your-client-secret',
companyConfig
);
// Run sync (via daily cron job)
downloader.runDailySync()
.then(() => console.log('β
Sync successful'))
.catch(err => console.error('β Sync error:', err));
π οΈ Development Toolsβ
Testing Script (bash)β
#!/bin/bash
# Script to test Max Capital API endpoints
# Usage: ./test_api.sh [environment]
ENVIRONMENT=${1:-dev}
if [ "$ENVIRONMENT" = "prod" ]; then
BASE_URL="https://api.max.capital"
else
BASE_URL="https://api-dev.max.capital"
fi
CLIENT_ID="demo-client-dev"
CLIENT_SECRET="your-client-secret"
echo "Testing Max Capital API in environment: $ENVIRONMENT"
echo "Base URL: $BASE_URL"
# 1. Authentication
echo "1. Authenticating..."
AUTH_RESPONSE=$(curl -s -X POST "$BASE_URL/auth/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"clientId\":\"$CLIENT_ID\",\"clientSecret\":\"$CLIENT_SECRET\"}")
if echo "$AUTH_RESPONSE" | grep -q "accessToken"; then
ACCESS_TOKEN=$(echo "$AUTH_RESPONSE" | jq -r '.accessToken')
echo "β
Authentication successful"
else
echo "β Authentication error:"
echo "$AUTH_RESPONSE"
exit 1
fi
# 2. Query fund
echo "2. Querying fund information..."
FUND_RESPONSE=$(curl -s -X GET "$BASE_URL/mutual-funds/api/v1/mutual-funds/3852" \
-H "Authorization: Bearer $ACCESS_TOKEN")
if echo "$FUND_RESPONSE" | grep -q "name"; then
FUND_NAME=$(echo "$FUND_RESPONSE" | jq -r '.name')
FUND_PRICE=$(echo "$FUND_RESPONSE" | jq -r '.price')
echo "β
Fund queried: $FUND_NAME - Price: \$$FUND_PRICE"
else
echo "β Error querying fund:"
echo "$FUND_RESPONSE"
fi
# 3. Query holdings (example)
echo "3. Querying holdings..."
HOLDINGS_RESPONSE=$(curl -s -X GET "$BASE_URL/mutual-funds/api/v1/mutual-funds-holdings" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-G \
-d "Date=$(date +%Y-%m-%d)" \
-d "accountHolderNumber=11772")
if echo "$HOLDINGS_RESPONSE" | grep -q "valuation"; then
VALUATION=$(echo "$HOLDINGS_RESPONSE" | jq -r '.valuation')
echo "β
Holdings queried - Valuation: \$$VALUATION"
else
echo "β Error querying holdings:"
echo "$HOLDINGS_RESPONSE"
fi
echo "π Tests completed"
These examples cover the most common use cases and provide a solid foundation for implementing integrations with Max Capital APIs. Each example includes error handling, automatic authentication, and development best practices.