Antes de empezar
Java 17 o superior
Y Spring Boot 3.
Una API key de pruebas de Flashpi
Guárdala en una variable de entorno, nunca en el código ni en el repositorio.
Tu certificado de firma .p12
Cargado en la cuenta de pruebas.
Tus datos de emisor
RUC, establecimiento y punto de emisión configurados en tu cuenta.
Paso 1 · Configura la aplicación
# src/main/resources/application.properties
flashpi.url=https://api.flashpi.ec/v1
flashpi.key=${FLASHPI_API_KEY}Y exporta la variable antes de arrancar: export FLASHPI_API_KEY="tu_api_key_de_pruebas".
Paso 2 · Crea el cliente
package ec.flashpi.demo;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class FlashpiClient {
private final HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
private final String baseUrl;
private final String apiKey;
public FlashpiClient(@Value("${flashpi.url}") String baseUrl,
@Value("${flashpi.key}") String apiKey) {
this.baseUrl = baseUrl;
this.apiKey = apiKey;
}
public String emitirFactura(String facturaJson) throws IOException, InterruptedException {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(baseUrl + "/facturas"))
.timeout(Duration.ofSeconds(30))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(facturaJson))
.build();
HttpResponse<String> response = http.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 400) {
throw new IllegalStateException("Flashpi " + response.statusCode() + ": " + response.body());
}
return response.body();
}
}Paso 3 · Expón un endpoint
package ec.flashpi.demo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FacturaController {
private final FlashpiClient flashpi;
public FacturaController(FlashpiClient flashpi) {
this.flashpi = flashpi;
}
@PostMapping(value = "/facturar", consumes = "application/json", produces = "application/json")
public String facturar(@RequestBody String facturaJson) throws Exception {
return flashpi.emitirFactura(facturaJson);
}
}Paso 4 · Pruébalo
./mvnw spring-boot:run
curl -X POST http://localhost:8080/facturar \
-H "Content-Type: application/json" \
-d '{
"comprador": {
"tipo_identificacion": "cedula",
"identificacion": "0102030405",
"razon_social": "Cliente de ejemplo",
"email": "[email protected]"
},
"detalles": [
{ "descripcion": "Servicio de ejemplo", "cantidad": 1, "precio_unitario": 25.00 }
]
}'Paso 5 · Pasa a producción con buenas prácticas
Maneja IllegalStateException con un @ControllerAdvice, usa @Async o una cola para no bloquear al usuario y registra la clave_acceso de cada comprobante. Si ya usas RestClient o WebClient, la lógica es la misma.
Errores frecuentes
| Síntoma | Causa probable | Qué hacer | Referencia |
|---|---|---|---|
401 Unauthorized | API key ausente, inválida o de otro ambiente. | Revisa el header Authorization y que uses la key del ambiente correcto. | Ver detalle |
422 Esquema XML | Algún campo no cumple la estructura esperada. | Lee el detalle del error y corrige el campo indicado. | Ver detalle |
SRI 43 | Clave de acceso ya registrada. | No reenvíes: consulta el estado del comprobante por su clave de acceso. | Ver detalle |
SRI 70 | Clave de acceso en procesamiento. | Espera unos segundos y consulta el estado. No reenvíes el comprobante. | Ver detalle |