Common Workflows
This guide covers common integration patterns and workflows for the Selva API.
Workflow 1: Payment Processing
Complete flow for processing a payment from validation to completion.
Step 1: Validate Payment
Before creating a payment, validate the payment details:
const validateResponse = await fetch('https://dev.selva.fi.cr/api/payments/validate', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
amount: 10000,
currency: 'CRC',
recipient_identifier: 'CR78037010600458074353',
}),
});
const validation = await validateResponse.json();
if (!validation.valid) {
console.error('Validation errors:', validation.errors);
// Handle validation errors
return;
}
Step 2: Create Payment
Once validated, create the payment with an idempotency key:
const idempotencyKey = crypto.randomUUID();
const paymentResponse = await fetch('https://dev.selva.fi.cr/api/payments', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
'X-Idempotency-Key': idempotencyKey,
},
body: JSON.stringify({
amount: 10000,
currency: 'CRC',
recipient_identifier: 'CR78037010600458074353',
description: 'Payment for services',
payment_method: 'transfer',
}),
});
const payment = await paymentResponse.json();
console.log('Payment created:', payment.id);
Step 3: Poll for Status
Check payment status until it's completed or failed:
async function waitForPaymentCompletion(paymentId) {
while (true) {
const response = await fetch(`https://dev.selva.fi.cr/api/payments/${paymentId}`, {
headers: {
'Authorization': `Bearer ${accessToken}`,
},
});
const payment = await response.json();
if (payment.status === 'completed') {
return payment;
}
if (payment.status === 'failed' || payment.status === 'cancelled') {
throw new Error(`Payment ${payment.status}`);
}
// Wait before polling again
await new Promise(resolve => setTimeout(resolve, 2000));
}
}
Workflow 2: Account Management
Complete flow for managing accounts and viewing transactions.
Create Account
const accountResponse = await fetch('https://dev.selva.fi.cr/api/accounts', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
currency: 'CRC',
}),
});
const account = await accountResponse.json();
console.log('Account created:', account.id);
Get Account Balance
const balanceResponse = await fetch(
`https://dev.selva.fi.cr/api/accounts/${accountId}/balance`,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
},
}
);
const balance = await balanceResponse.json();
console.log(`Balance: ${balance.currency} ${balance.balance}`);
View Account Movements
const movementsResponse = await fetch(
`https://dev.selva.fi.cr/api/accounts/${accountId}/movements?start_date=2024-01-01T00:00:00Z&end_date=2024-12-31T23:59:59Z`,
{
headers: {
'Authorization': `Bearer ${accessToken}`,
},
}
);
const movements = await movementsResponse.json();
console.log('Account movements:', movements);
Workflow 3: Webhook Integration
Set up webhooks to receive real-time notifications.
Step 1: Create Webhook Subscription
const webhookResponse = await fetch('https://dev.selva.fi.cr/api/webhooks/subscriptions', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: 'https://your-app.com/webhooks',
events: 'payment.completed,payment.failed,account.created',
max_attempts: '3',
headers: {
'X-Custom-Header': 'custom-value',
},
}),
});
const subscription = await webhookResponse.json();
console.log('Webhook subscription created:', subscription.id);
Step 2: Handle Webhook Events
Implement a webhook endpoint in your application:
// Express.js example
app.post('/webhooks', async (req, res) => {
const signature = req.headers['signature'];
const payload = req.body;
// Verify webhook signature
if (!verifySignature(signature, payload)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Handle different event types
if (payload.event === 'payment.completed') {
await handlePaymentCompleted(payload.data);
} else if (payload.event === 'payment.failed') {
await handlePaymentFailed(payload.data);
}
res.status(200).json({ status: 'received' });
});
Step 3: Handle Incoming Transfers
For incoming transfer notifications:
app.post('/webhooks/incoming-transfers', async (req, res) => {
const signature = req.headers['signature'];
const notification = req.body;
// Verify signature
if (!verifySignature(signature, notification)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process each transfer
for (const transfer of notification.Transfers) {
await processIncomingTransfer(transfer);
}
res.status(200).json({ status: 'received' });
});
Workflow 4: Verification Services
Verify account information before processing payments.
Verify IBAN
const ibanResponse = await fetch('https://dev.selva.fi.cr/api/iban/information', {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
iban: 'CR78037010600458074353',
}),
});
const ibanInfo = await ibanResponse.json();
if (ibanInfo.valid) {
console.log('IBAN is valid:', ibanInfo.account_holder);
} else {
console.error('Invalid IBAN');
}
Verify Phone Number
const phoneResponse = await fetch(
'https://dev.selva.fi.cr/api/phone/information?phone_number=+50688888888',
{
headers: {
'Authorization': `Bearer ${accessToken}`,
},
}
);
const phoneInfo = await phoneResponse.json();
console.log('Phone verified:', phoneInfo.verified);
Workflow 5: Error Handling and Retries
Implement robust error handling with exponential backoff.
async function apiCallWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return await response.json();
}
// Don't retry on client errors (4xx)
if (response.status >= 400 && response.status < 500) {
const error = await response.json();
throw new Error(error.message);
}
// Retry on server errors (5xx)
if (response.status >= 500) {
throw new Error('Server error');
}
} catch (error) {
if (attempt === maxRetries - 1) {
throw error;
}
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
try {
const accounts = await apiCallWithRetry(
'https://dev.selva.fi.cr/api/accounts',
{
headers: {
'Authorization': `Bearer ${accessToken}`,
},
}
);
} catch (error) {
console.error('API call failed:', error);
}
Best Practices
- Always validate payments before creating them
- Use idempotency keys for payment requests
- Implement webhook signature verification for security
- Handle rate limits with exponential backoff
- Store access tokens securely and refresh them before expiration
- Log all API calls for debugging and auditing
- Handle errors gracefully with user-friendly messages
Next Steps
- Review the API Reference for all available endpoints
- Check the Error Handling guide for error codes and strategies
- See Authentication for token management