RPAfelApi Enhancements
Date: 2025-01-21
Status: Implemented
Overview
This document describes the enhancements made to the RPAfelApi integration based on the official API documentation.
New Features
1. GetToken Endpoint Support ✅
Implementation: ProviderRpaFelApiService.getToken()
- Purpose: Retrieve authentication tokens from RPAfelApi
- Caching: Tokens are cached with expiration tracking
- Auto-refresh: Tokens are refreshed 5 minutes before expiration
- Usage:
const provider = providerService.getProvider("rpafelapi");
const token = await provider.getToken(userName, password);
Benefits:
- Reduces API calls by caching tokens
- Automatic token refresh
- Better error handling
2. Void Certificate Endpoint ✅
Implementation: ProviderRpaFelApiService.voidCertificate()
- Purpose: Cancel/void existing certificates
- Endpoint:
POST /api/fel/voidCertificate - Usage:
const voidRequest: RpaFelApiVoidRequest = {
NumeroDocumentoAAnular: "A-123456",
NITEmisor: "44653948",
IDReceptor: "49862952",
FechaEmisionDocumentoAnular: "2024-01-15T10:30:00",
FechaHoraAnulacion: "2024-01-15T11:00:00",
MotivoAnulacion: "Error en facturación",
Gface: "Digifact",
rpaCertificador_Usuario: "GT.000044653948.RPA_TEST"
};
const result = await provider.voidCertificate(voidRequest, token);
3. Email Notification Endpoint ✅
Implementation: ProviderRpaFelApiService.sendEmail()
- Purpose: Queue email notifications for certificates
- Endpoint:
POST /api/fel/mailFel - Usage:
const mailRequest: RpaFelApiMailRequest = {
rpaUUID: "550e8400-e29b-41d4-a716-446655440000",
emails: ["customer@example.com", "accounting@example.com"]
};
const result = await provider.sendEmail(mailRequest);
4. Enhanced Error Handling ✅
Features:
- Retry Logic: Automatic retry with exponential backoff
- Transient Failure Handling: Retries on 401, 406, and 5xx errors
- Better Logging: Structured logging with context
- Error Preservation: Full error details preserved for upstream handlers
Configuration:
- Max retries: 3
- Initial delay: 1 second
- Exponential backoff: 2^attempt
5. Special Case Handling ✅
Tip (Propina) Support
- Detection: Automatically detects tip items by name ("PROPINA" or "TIP")
- Flag: Sets
PropinaAdenda: "1"inextraobject when tip is detected - Implementation:
XmlToDteJsonService.hasTipItem()
CUI Identification Type
- Support: Handles CUI identification via
TipoEspecialfield - Mapping:
receiverData.taxpayerType→extra.TipoEspecial
Special NIT Phrase Handling
- Detection: Identifies special NITs that require additional phrases
- Special NITs:
87605473,96167416,11700207K,14945908 - Implementation:
ProviderRpaFelApiService.requiresSpecialPhrase()
6. Token Caching ✅
Features:
- In-memory cache with expiration tracking
- Automatic cache invalidation
- Per-user token caching
- Cache clearing utility
Cache Structure:
interface CachedToken {
token: string;
expiresAt: Date;
userName: string;
}
Updated Interfaces
New Types
// Token Management
interface RpaFelApiTokenRequest {
UserName: string;
Password: string;
}
interface RpaFelApiTokenResponse {
Success: boolean;
response: {
token: string;
expira_en: string;
otorgado_a: string;
};
}
// Void Certificate
interface RpaFelApiVoidRequest {
NumeroDocumentoAAnular: string;
NITEmisor: string;
IDReceptor: string;
FechaEmisionDocumentoAnular: string;
FechaHoraAnulacion: string;
MotivoAnulacion: string;
Gface: string;
rpaCertificador_Usuario: string;
}
interface RpaFelApiVoidResponse {
ok: boolean;
voidID?: string;
data?: { /* ... */ };
}
// Email
interface RpaFelApiMailRequest {
rpaUUID: string;
emails: string[];
}
interface RpaFelApiMailResponse {
id: string;
}
Enhanced DTE JSON
interface DteJson {
// ... existing fields
extra?: {
subDomain?: string;
TipoEspecial?: string;
PropinaAdenda?: string; // NEW: Tip flag
};
}
Usage Examples
Complete Workflow
// 1. Get token (with caching)
const provider = providerService.getProvider("rpafelapi");
const token = await provider.getToken(userName, password);
// 2. Generate certificate
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
const certificate = await provider.certifyDocument({
taxId,
xmlContent: JSON.stringify(dteJson),
apiUrl: "",
token
});
// 3. Send email notification
await provider.sendEmail({
rpaUUID: certificate.rpaUUID,
emails: ["customer@example.com"]
});
// 4. Void certificate (if needed)
await provider.voidCertificate({
NumeroDocumentoAAnular: certificate.Autorizacion,
NITEmisor: taxId,
IDReceptor: receiverTaxId,
FechaEmisionDocumentoAnular: certificate.Fecha_DTE,
FechaHoraAnulacion: new Date().toISOString(),
MotivoAnulacion: "Error en facturación",
Gface: "Digifact",
rpaCertificador_Usuario: userName
}, token);
Tip Handling
// Invoice with tip item
const invoice: Invoice = {
// ... other fields
items: [
{
name: "Meal",
// ... other item fields
},
{
name: "PROPINA", // Tip item detected automatically
// ... other item fields
}
]
};
// PropinaAdenda flag is automatically set to "1"
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
// dteJson.extra.PropinaAdenda === "1"
CUI Identification
const invoice: Invoice = {
// ... other fields
receiverData: {
taxId: "2260269730101", // CUI format
taxName: "Customer Name",
taxpayerType: "CUI", // Set to CUI
// ... other fields
}
};
// TipoEspecial is automatically set in extra
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(invoice, rpaUUID);
// dteJson.extra.TipoEspecial === "CUI"
Error Handling
Retry Logic
The service automatically retries failed requests with exponential backoff:
// Automatic retry on transient failures
try {
const result = await provider.certifyDocument({ /* ... */ });
} catch (error) {
// Retries automatically on:
// - 401 Unauthorized (token refresh)
// - 406 Not Acceptable (already signed)
// - 5xx Server errors
// Does NOT retry on:
// - 400 Bad Request (client error)
// - 403 Forbidden (authorization error)
}
Error Response Structure
// Enhanced error object
{
message: string;
response?: {
status: number;
statusText: string;
data: any;
};
responseData?: any; // Full error response from API
}
Configuration
Environment Variables
# RPAfelApi URL (optional, defaults based on NODE_ENV)
RPA_FEL_API_URL=https://fel.rpapos.com/api/fel
# For development
RPA_FEL_API_URL=https://fel-dev.rpapos.com/api/fel
Retry Configuration
Currently hardcoded but can be made configurable:
private readonly maxRetries = 3;
private readonly retryDelay = 1000; // 1 second
Testing
Unit Tests
All new methods should have unit tests covering:
- Token caching and expiration
- Retry logic
- Error handling
- Special case detection
Integration Tests
Test scenarios:
- Token retrieval and caching
- Certificate generation with retry
- Void certificate flow
- Email notification
- Tip detection
- CUI identification
- Special NIT phrase handling
Migration Notes
Breaking Changes
None - all changes are backward compatible.
Deprecations
- Direct password usage in Authorization header (still works, but GetToken is preferred)
Recommendations
- Use GetToken: Always use
getToken()instead of passing password directly - Handle Errors: Implement proper error handling for retry scenarios
- Monitor Cache: Clear token cache if authentication issues occur
- Use Email Endpoint: Use
sendEmail()for better email delivery tracking
Future Enhancements
- GetSignedCertificate Endpoint: Implement retrieval of signed certificates
- Pub/Sub Integration: Subscribe to certification events
- Configurable Retry: Make retry parameters configurable
- Token Refresh Background Job: Automatic token refresh before expiration
- Metrics/Monitoring: Add metrics for API calls, cache hits, retries
References
Last Updated: 2025-01-21
Maintained By: FEL Team