Antes de empezar
Un backend propio
El ejemplo usa Node y Express, pero sirve cualquiera.
Tu API key de pruebas de Flashpi
Paso 1 · Entiende por qué no llamar a la API desde el navegador
Todo lo que corre en el navegador es visible: cualquiera puede abrir las herramientas de desarrollo y copiar tu API key. Con esa key podrían emitir comprobantes a tu nombre.
Paso 2 · Crea el backend intermedio
// server.mjs
import express from "express";
const app = express();
app.use(express.json());
const BASE_URL = "https://api.flashpi.ec/v1";
const API_KEY = process.env.FLASHPI_API_KEY; // vive solo en el servidor
app.get("/api/facturas/:claveAcceso", async (req, res) => {
// Aquí valida que el usuario autenticado tenga permiso sobre esta factura.
try {
const r = await fetch(
`${BASE_URL}/comprobantes/${encodeURIComponent(req.params.claveAcceso)}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
);
const data = await r.json();
// Devuelve solo lo que el navegador necesita
res.status(r.status).json({ estado: data.estado, clave_acceso: data.clave_acceso });
} catch (err) {
res.status(502).json({ error: "No se pudo consultar el comprobante" });
}
});
app.listen(3000, () => console.log("Backend en http://localhost:3000"));Instala y ejecuta: npm install express y FLASHPI_API_KEY=... node server.mjs.
Paso 3 · Consúmelo desde React
// EstadoFactura.jsx
import { useEffect, useState } from "react";
export function EstadoFactura({ claveAcceso }) {
const [estado, setEstado] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetch(`/api/facturas/${claveAcceso}`)
.then((r) => (r.ok ? r.json() : Promise.reject(new Error(`Error ${r.status}`))))
.then(setEstado)
.catch((e) => setError(e.message));
}, [claveAcceso]);
if (error) return <p>No se pudo consultar: {error}</p>;
if (!estado) return <p>Consultando…</p>;
return <p>Estado: {estado.estado}</p>;
}Paso 4 · Consúmelo desde Vue
<!-- EstadoFactura.vue -->
<script setup>
import { ref, onMounted } from "vue";
const props = defineProps({ claveAcceso: String });
const estado = ref(null);
const error = ref(null);
onMounted(async () => {
try {
const r = await fetch(`/api/facturas/${props.claveAcceso}`);
if (!r.ok) throw new Error(`Error ${r.status}`);
estado.value = await r.json();
} catch (e) {
error.value = e.message;
}
});
</script>
<template>
<p v-if="error">No se pudo consultar: {{ error }}</p>
<p v-else-if="!estado">Consultando…</p>
<p v-else>Estado: {{ estado.estado }}</p>
</template>Paso 5 · Consúmelo desde Angular
// facturas.service.ts
import { Injectable, inject } from "@angular/core";
import { HttpClient } from "@angular/common/http";
@Injectable({ providedIn: "root" })
export class FacturasService {
private http = inject(HttpClient);
estado(claveAcceso: string) {
return this.http.get<{ estado: string }>(`/api/facturas/${claveAcceso}`);
}
}Recuerda registrar provideHttpClient() en la configuración de tu aplicación.
Paso 6 · Consúmelo desde Svelte
<!-- EstadoFactura.svelte -->
<script>
export let claveAcceso;
const consulta = fetch(`/api/facturas/${claveAcceso}`).then((r) => {
if (!r.ok) throw new Error(`Error ${r.status}`);
return r.json();
});
</script>
{#await consulta}
<p>Consultando…</p>
{:then estado}
<p>Estado: {estado.estado}</p>
{:catch error}
<p>No se pudo consultar: {error.message}</p>
{/await}Este ejemplo usa la sintaxis de Svelte 3 y 4, que también funciona en Svelte 5.
Paso 7 · Protege tu backend
- Autentica a tus usuarios y verifica que cada uno solo vea sus facturas.
- Devuelve al navegador solo los campos necesarios.
- Configura CORS para aceptar solo tu dominio.
- Limita la cantidad de solicitudes por usuario.
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 |
SRI 70 | Clave de acceso en procesamiento. | Espera unos segundos y consulta el estado. No reenvíes el comprobante. | Ver detalle |