#
Communication Protocols
The Valu API ecosystem implements multiple communication protocols to ensure secure, efficient, and reliable data exchange between mobile applications, backend services, and external APIs.
#
Mobile App to Valu API Communication
#
Authentication Protocol
sequenceDiagram
participant App as Mobile App
participant API as Valu API
participant DB as Database
Note over App: User enters/generates seed
App->>App: Generate bearer token from seed
rect rgb(240, 248, 255)
Note over App,API: Initial Authentication
App->>API: POST /sessions/auth/key
Note right of App: {secretKey: bearerToken, network: "VRSC|VRSCTEST"}
API->>DB: SELECT * FROM users WHERE password = ?
alt User not found
API->>DB: INSERT new user with UUID
Note right of API: Generate new API key
else User exists
Note right of API: Use existing API key
end
DB-->>API: User record with API key
API-->>App: {authenticatedAs: userId, apiKey: key, success: true}
end
App->>App: Store credentials & setup request interceptors
rect rgb(248, 255, 248)
Note over App,API: Subsequent API Calls
App->>API: Signed API Request
Note right of App: Headers: x-api-signature, x-api-key, x-payload-digest-alg
API->>API: Verify signature & authenticate
API-->>App: Protected response
end
#
Request Signing Implementation
Mobile App Request Interceptor:
authenticate(valuToken, apiKey) {
this.authInterceptor = this.service.interceptors.request.use(
(config) => {
// Add timestamp to prevent replay attacks
config.url = config.url.includes("timestamp")
? config.url
: config.url + `?timestamp=${Date.now()}`;
// Sign based on HTTP method
if (config.method === "get") {
config.headers["x-api-signature"] = ValuService.signUrlString(
axios.getUri(config),
valuToken
);
} else {
let uri = axios.getUri(config);
if (uri.substr(0, 4) !== "http") {
uri = config.baseURL.replace(/\/+$/, "") + uri;
}
// Sign URL + JSON body for POST/PUT requests
config.headers["x-api-signature"] = ValuService.signUrlString(
config.data == null ? uri : uri + JSON.stringify(config.data),
valuToken
);
}
config.headers["x-payload-digest-alg"] = "sha256";
config.headers["x-api-key"] = apiKey;
return config;
}
);
}
#
Bearer Token Generation
flowchart TD
Seed["User Seed (BIP39 Mnemonic)"] --> Convert["mnemonicToSeed()"]
Convert --> Hash1["SHA-256 Hash"]
ServiceID["VALU_SERVICE_ID (Canonical Buffer)"] --> Hash1
Hash1 --> Hash2["RIPEMD-160 Hash"]
Hash2 --> Token["Bearer Token (40 character hex)"]
classDef input fill:#e1f5fe
classDef process fill:#f3e5f5
classDef output fill:#e8f5e8
class Seed,ServiceID input
class Convert,Hash1,Hash2 process
class Token outputImplementation:
static bearerFromSeed = async (seed) => {
var ripemd160 = crypto.createHash("ripemd160");
var sha256 = crypto.createHash("sha256");
const VALU_SERVICE_CANONICAL = Buffer.from(VALU_SERVICE_ID, "utf8");
const sha256Hash = sha256
.update(await mnemonicToSeed(seed))
.update(VALU_SERVICE_CANONICAL)
.digest();
return ripemd160.update(sha256Hash).digest().toString("hex");
};
#
External API Integrations
#
Sumsub KYC Communication
sequenceDiagram
participant VA as Valu API
participant SB as Sumsub API
rect rgb(255, 248, 240)
Note over VA,SB: Request Preparation
VA->>VA: Generate Unix timestamp
VA->>VA: Create signature payload
Note right of VA: timestamp + method + url + body
VA->>VA: HMAC-SHA256 signature
end
rect rgb(240, 255, 248)
Note over VA,SB: Authenticated Request
VA->>SB: HTTP Request with headers
Note right of VA: X-App-Token, X-App-Access-Sig, X-App-Access-Ts
SB->>SB: Verify timestamp (±10 minutes)
SB->>SB: Recreate signature & compare
SB-->>VA: KYC operation response
endSumsub Authentication Builder:
const getSigBuilder = (apiToken, secretKey) => config => {
const timestamp = Math.floor(Date.now() / 1000)
const signature = crypto.createHmac('sha256', secretKey)
// Build signature payload
signature.update(`${timestamp}${_.toUpper(config.method)}${config.url}`)
if (config.data instanceof FormData) {
signature.update(config.data.getBuffer())
} else if (config.data) {
signature.update(JSON.stringify(config.data))
}
// Set authentication headers
config.headers['X-App-Token'] = apiToken
config.headers['X-App-Access-Sig'] = signature.digest('hex')
config.headers['X-App-Access-Ts'] = timestamp
return config
}
#
Paybis Payment Integration
sequenceDiagram
participant VA as Valu API
participant PB as Paybis API
rect rgb(255, 240, 245)
Note over VA,PB: RSA Signature Process
VA->>VA: Serialize request body to JSON
VA->>VA: SHA-512 hash of JSON string
VA->>VA: RSA-PSS sign with private key
Note right of VA: PKCS1_PSS_PADDING + SALTLEN_DIGEST
VA->>VA: Base64 encode signature
end
rect rgb(240, 248, 255)
Note over VA,PB: Payment Request
VA->>PB: POST with X-Request-Signature header
Note right of VA: Authorization: Bearer token
PB->>PB: Verify RSA signature
PB->>PB: Process payment operation
PB-->>VA: Payment response
endRSA Signature Implementation:
const getSigBuilder = (privateKey) => config => {
if (!config.data) return config
// Hash the request body
const hash = crypto.createHash('sha512');
const hashedData = hash.update(JSON.stringify(config.data), 'utf-8').digest('hex');
// Create RSA-PSS signature
const signature = crypto.sign("sha512", Buffer.from(hashedData), {
key: privateKey,
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST,
})
config.headers['X-Request-Signature'] = signature.toString('base64')
return config
}
#
Stripe Payment Processing
flowchart LR
VA[Valu API] --> Auth[Bearer Token Auth]
Auth --> Request[HTTPS Request]
Request --> Stripe[Stripe API]
Stripe --> Response[JSON Response]
subgraph "Request Flow"
Headers[Authorization Header<br/>Content-Type: application/json]
TLS[TLS 1.3 Encryption]
Webhook[Webhook Verification<br/>Stripe-Signature]
end
Auth --> Headers
Request --> TLS
Response --> WebhookStripe Authentication:
const getStripeQuote = async (countryCode) => {
const convertedCountryCode = getCountryCodeAndCurrency(countryCode);
const url = new URL('https://api.stripe.com/v1/crypto/onramp_quotes');
url.searchParams.append('source_amount', 1000);
url.searchParams.append('destination_currencies[]', "usdc");
url.searchParams.append('destination_networks[]', 'ethereum');
url.searchParams.append('source_currency', convertedCountryCode.currency.toLowerCase());
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${process.env.STRIPE_SK}`,
'Content-Type': 'application/json'
}
});
return response.json();
}
#
Blockchain Communication Protocols
#
Verus Blockchain RPC
sequenceDiagram
participant VA as Valu API
participant VD as Verus Daemon
rect rgb(248, 255, 248)
Note over VA,VD: RPC Authentication
VA->>VD: HTTP Basic Auth Request
Note right of VA: Username: REMOTE_USER<br/>Password: REMOTE_PASS
VD->>VD: Validate credentials
end
rect rgb(240, 248, 255)
Note over VA,VD: RPC Commands
VA->>VD: JSON-RPC 2.0 Request
Note right of VA: {"method": "getinfo", "params": [], "id": 1}
VD->>VD: Execute blockchain operation
VD-->>VA: JSON-RPC Response
Note left of VD: {"result": {...}, "error": null, "id": 1}
endVerus RPC Configuration:
// Environment configuration
const VERUS_CONFIG = {
protocol: process.env.REMOTE_PROTOCOL || "http",
host: process.env.REMOTE_HOST,
port: process.env.REMOTE_PORT,
username: process.env.REMOTE_USER,
password: process.env.REMOTE_PASS
};
const rpcCall = async (method, params = []) => {
const request = {
jsonrpc: "2.0",
method: method,
params: params,
id: Math.floor(Math.random() * 1000000)
};
const response = await axios.post(
`${VERUS_CONFIG.protocol}://${VERUS_CONFIG.host}:${VERUS_CONFIG.port}`,
request,
{
auth: {
username: VERUS_CONFIG.username,
password: VERUS_CONFIG.password
}
}
);
return response.data.result;
};
#
Polygon Blockchain Integration
sequenceDiagram
participant VA as Valu API
participant PP as Polygon Provider
participant PC as Polygon Contract
rect rgb(255, 248, 240)
Note over VA,PP: Provider Connection
VA->>PP: Connect to RPC endpoint
Note right of VA: https://rpc-amoy.polygon.technology/
PP-->>VA: Connection established
end
rect rgb(248, 255, 248)
Note over VA,PC: Transaction Flow
VA->>VA: Create wallet instance with private key
VA->>PC: Contract.transfer(address, amount)
PC->>PP: Submit transaction to network
PP->>PP: Mine transaction in block
PP-->>VA: Transaction hash & receipt
endPolygon Transaction Implementation:
const { JsonRpcProvider, Wallet, parseUnits, Contract } = require("ethers");
// Initialize provider and wallet
const provider = new JsonRpcProvider("https://rpc-amoy.polygon.technology/");
const wallet = new Wallet(process.env.POLYGON_AMOY_PRIVATE_KEY, provider);
async function payUSDC(toAddress, amount) {
try {
// Validate recipient address
if (!isAddress(toAddress)) {
throw new Error("Invalid recipient address");
}
// Setup USDC contract
const usdcContractAddress = process.env.USDC_AMOY_CONTRACT_ADDRESS;
const usdcAbi = ["function transfer(address to, uint256 amount) public returns (bool)"];
const usdcContract = new Contract(usdcContractAddress, usdcAbi, wallet);
// Convert amount to proper decimals (USDC uses 6 decimals)
const amountInSmallestUnit = parseUnits(amount, 6);
// Execute transaction
const transactionResponse = await usdcContract.transfer(toAddress, amountInSmallestUnit);
console.log("Transaction sent:", transactionResponse.hash);
// Wait for confirmation
await transactionResponse.wait();
console.log("Transaction confirmed:", transactionResponse.hash);
return transactionResponse.hash;
} catch (error) {
console.error("Error sending USDC payment:", error);
throw error;
}
}
#
Database Communication
#
SQL Server Connection Protocol
flowchart TD
subgraph "Connection Pool"
Pool[MySQL Connection Pool<br/>Max: 100 connections]
Pool --> Conn1[Connection 1<br/>Active]
Pool --> Conn2[Connection 2<br/>Idle]
Pool --> ConnN[Connection N<br/>Available]
end
subgraph "Query Processing"
Query[SQL Query] --> Prepare[Prepared Statement]
Prepare --> Execute[Execute with Parameters]
Execute --> Result[Result Set]
end
subgraph "Security"
SSL[SSL/TLS Encryption]
Auth[Database Authentication]
Audit[Query Auditing]
end
Pool --> Query
Query --> SSL
SSL --> Auth
Auth --> AuditDatabase Configuration:
const mysql = require('mysql2/promise');
const pool = mysql.createPool({
host: process.env.DB_HOST,
port: process.env.DB_PORT,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
waitForConnections: true,
connectionLimit: 100,
queueLimit: 0,
ssl: {
rejectUnauthorized: false // Configure based on SSL setup
},
acquireTimeout: 60000,
timeout: 60000
});
// User creation with parameterized queries
exports.setNewUserforPOL = async (api_key, password, status, network) => {
const userId = uuidv4();
// Insert new user
const result = await pool.query(
'INSERT INTO users (id, status, password, api_key, network) VALUES (?, ?, ?, ?, ?)',
[userId, status, password, api_key, network]
);
// Retrieve created user
const userResult = await pool.query(
'SELECT * FROM users WHERE id = ?',
[userId]
);
return userResult[0];
};
#
Inter-Service Communication Patterns
#
Synchronous vs Asynchronous Communication
graph TB
subgraph "Synchronous (Real-time)"
S1[User Authentication] --> S2[KYC Verification]
S3[Payment Processing] --> S4[Blockchain Transactions]
end
subgraph "Asynchronous (Event-driven)"
A1[Webhook Processing] --> Queue[Message Queue]
Queue --> A2[Background Jobs]
A2 --> A3[Notification Delivery]
end
subgraph "Hybrid Patterns"
H1[Initial Request] --> H2[Immediate Response]
H2 --> H3[Background Processing]
H3 --> H4[Callback/Webhook]
end
#
Error Handling & Retry Logic
sequenceDiagram
participant Client
participant API as Valu API
participant Service as External Service
Client->>API: Request
API->>Service: Service Call
alt Success
Service-->>API: Success Response
API-->>Client: Success
else Temporary Error
Service-->>API: 5xx Error
API->>API: Wait (exponential backoff)
API->>Service: Retry Request
Service-->>API: Success Response
API-->>Client: Success
else Permanent Error
Service-->>API: 4xx Error
API-->>Client: Error Response
else Timeout
Service-->>API: Timeout
API->>API: Log & Alert
API-->>Client: Service Unavailable
endRetry Implementation:
const retryWithBackoff = async (fn, maxRetries = 3, baseDelay = 1000) => {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
// Check if error is retryable
if (error.response && error.response.status < 500) {
throw error; // Don't retry client errors
}
// Exponential backoff with jitter
const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
Version Header Implementation:
// Client specifies API version
config.headers['API-Version'] = '2.0';
// Server handles version routing
app.use('/api/v1', v1Router);
app.use('/api/v2', v2Router);
app.use('/api/v3', v3Router);
// Default to latest stable version
app.use('/api', v2Router);
This comprehensive communication protocol documentation ensures secure, efficient, and scalable interactions across the entire Valu ecosystem.