How Multi-Tenancy Works
JSIFEN uses a request-scoped context to identify which client’s configuration to use:- Emisor Header: API requests include an
Emisorheader with the client identifier - EmisorContext: A request-scoped bean stores the current client identifier
- Configuration Resolution: Configuration is loaded based on the client identifier
EmisorContext class (EmisorContext.java:6) is a request-scoped CDI bean that maintains the current client context throughout the request lifecycle.
Configuration Pattern
Multi-tenant configuration follows a naming pattern insifen.properties:
{CLIENT_ID} with your client identifier (e.g., sanantonio, cliente1, empresa-abc).
Setting Up Multiple Clients
Configure the default client
Set up the default configuration that will be used when no
Emisor header is provided:Complete Multi-Tenant Example
sifen.properties
Using the Emisor Header
All JSIFEN API endpoints support the optionalEmisor header for multi-tenant requests.
Header Specification
The client identifier matching the configuration prefix in
sifen.properties.- Optional: If not provided, the default configuration is used
- Case-sensitive: Must match the prefix exactly (e.g.,
sanantonionotSanAntonio) - No special characters: Use simple identifiers (letters, numbers, hyphens, underscores)
API Request Examples
Using Default Configuration
When noEmisor header is provided, the default configuration (sifen.*) is used:
Using Client-Specific Configuration
Provide theEmisor header to use a specific client’s configuration:
JavaScript/Fetch Example
Java Example
How Configuration Resolution Works
TheSifenProperties class (SifenProperties.java:50-55) implements the configuration resolution logic:
- Request arrives with
Emisor: sanantonioheader EmisorContext.setEmisor("sanantonio")is called (ConsultaRucResource.java:39)- When configuration is needed,
SifenPropertieslooks forsifen.sanantonio.ambiente - If found, uses client-specific value; otherwise falls back to default
- Certificate and credentials are loaded for that specific client
EmisorContext Usage in Code
TheEmisorContext is injected into resources and used throughout the request:
ConsultaRucResource.java
EmisorContext.java:5), so it’s automatically cleaned up after the request completes.
Configuration Best Practices
Naming Conventions
- Use lowercase client identifiers:
sanantonio, notSanAntonio - Use hyphens or underscores for multi-word names:
empresa-abcorempresa_abc - Keep identifiers short and descriptive
- Avoid special characters that might cause issues in headers
Security Considerations
- Store each client’s certificate in a separate file
- Use different passwords for each client’s certificate
- Apply appropriate file permissions to each certificate
- Consider using environment variables for sensitive values:
Environment Separation
You can mix production and test environments for different clients:Testing Multi-Tenant Setup
Verify Configuration Loading
Use theprintConfig method to debug configuration (SifenProperties.java:111-120):
Test API Endpoints
Test each client configuration:Supported Endpoints
All JSIFEN endpoints support theEmisor header:
POST /consulta/ruc- RUC consultation (ConsultaRucResource.java:31)POST /consulta/de- DE consultation (ConsultaDEResource.java:45)POST /consulta/lote- Batch consultation (ConsultaLoteResource.java:35)POST /factura/xml/generar- Generate invoice XML (FacturaXmlGenerarResource.java:35)POST /factura/recibe- Receive invoice (AsyncRecibeResource.java:41)POST /evento/cancelar- Cancel event (EventoCancelarResource.java:34)
Troubleshooting
Configuration Not Found
If a client configuration is missing, JSIFEN falls back to the default configuration. To ensure client-specific configuration is used:- Verify the property prefix matches the
Emisorheader exactly - Check for typos in property names
- Ensure all required properties are set for that client
Wrong Certificate Used
If the wrong certificate is being used:- Check that
sifen.{CLIENT_ID}.keystore.pathis set correctly - Verify the
Emisorheader is being sent in the request - Check the application logs for “Emisor actual: …” messages (
EmisorContext.java:11)
Header Not Recognized
If theEmisor header is not being recognized:
- Ensure the header name is exactly
Emisor(case-sensitive) - Verify your HTTP client is sending the header correctly
- Check for any proxy or middleware that might be removing headers
Next Steps
- Review certificate management for each client
- Set up SIFEN credentials for each tenant
- Explore the API Reference for all supported endpoints