Cómo integrar una API de RUC de Ecuador
Publicado el
Consultar un RUC desde una API ayuda a completar datos de facturación, revisar proveedores y reducir errores al registrar clientes o empresas ecuatorianas.
Este tutorial muestra una integración completa del endpoint de RUC: formato del identificador, autenticación Bearer, ejemplos en cuatro lenguajes, respuesta JSON y controles para usarla de forma segura en producción.
Qué devuelve el endpoint de RUC
Usa GET /api/v1/rucs/{ruc} con un RUC de 13 dígitos. La respuesta puede incluir razón social, nombre comercial, estado, tipo de contribuyente, actividad económica, dirección y establecimientos.
El estado y los establecimientos son datos que tu aplicación debe interpretar, no una garantía comercial. Diseña tu flujo para admitir campos null, listas vacías y actualizaciones posteriores.
Requisitos antes de integrar
- Crea una API key y configúrala como ECUADORAPI_KEY en el entorno del servidor.
- Valida que el RUC contenga 13 dígitos antes de enviarlo.
- No expongas la clave en aplicaciones web, móviles ni repositorios públicos.
- Define qué campos necesitas para facturación, proveedores o registro y evita conservar el resto sin propósito.
Ejemplos para consultar un RUC desde código
Copia el ejemplo de tu lenguaje y reemplaza el RUC ficticio. La API devuelve el mismo envelope JSON en todos los casos.
GET /api/v1/rucs/{ruc}El ejemplo usa un identificador ficticio. Reemplázalo por el dato que necesitas consultar.
curl --request GET "https://api.ecuadorapi.com/api/v1/rucs/1790012345001" \
--header "Authorization: Bearer $ECUADORAPI_KEY" \
--header "Accept: application/json" \
--fail-with-body \
--max-time 60const response = await fetch("https://api.ecuadorapi.com/api/v1/rucs/1790012345001", {
headers: {
Authorization: "Bearer " + process.env.ECUADORAPI_KEY,
Accept: "application/json",
},
signal: AbortSignal.timeout(60_000),
})
const contentType = response.headers.get("content-type") ?? ""
const body = contentType.includes("json")
? await response.json().catch(() => null)
: null
if (!response.ok || body?.error) {
throw new Error(body?.message ?? "Request failed: " + response.status)
}
if (!body || !("data" in body)) {
throw new Error("API returned an invalid response")
}
const result = body.data
// Use result in your server-side flow. Avoid logging personal responses.import os, requests
response = requests.get(
"https://api.ecuadorapi.com/api/v1/rucs/1790012345001",
headers={
"Authorization": f"Bearer {os.environ['ECUADORAPI_KEY']}",
"Accept": "application/json",
},
timeout=60,
)
content_type = response.headers.get("content-type", "")
try:
body = response.json() if "json" in content_type else None
except requests.exceptions.JSONDecodeError:
body = None
if not response.ok or (isinstance(body, dict) and body.get("error")):
message = body.get("message") if isinstance(body, dict) else None
raise RuntimeError(message or f"Request failed: {response.status_code}")
if not isinstance(body, dict) or "data" not in body:
raise RuntimeError("API returned an invalid response")
data = body["data"]
# Use data in your server-side flow. Avoid logging personal responses.$ch = curl_init("https://api.ecuadorapi.com/api/v1/rucs/1790012345001");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . getenv("ECUADORAPI_KEY"),
"Accept: application/json",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
$rawBody = curl_exec($ch);
if ($rawBody === false) {
$transportError = curl_error($ch);
curl_close($ch);
throw new RuntimeException("Request transport failed: " . $transportError);
}
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$body = json_decode($rawBody, true);
if (!is_array($body)) {
throw new RuntimeException("API returned invalid JSON");
}
if ($statusCode >= 400 || ($body["error"] ?? false)) {
throw new RuntimeException(
($body["message"] ?? null) ?: "Request failed: " . $statusCode
);
}
if (!array_key_exists("data", $body)) {
throw new RuntimeException("API returned an invalid response");
}
$data = $body["data"];
// Use $data in your server-side flow. Avoid logging personal responses.Respuesta de ejemplo · 200 OK
JSON ficticio con la misma estructura que devuelve la API. Verlo o copiarlo no consume saldo.
{
"data": {
"id": "1790012345001",
"business_name": "EJEMPLO COMERCIAL S.A.",
"trade_name": "EJEMPLO",
"status": "ACTIVO",
"taxpayer_type": "SOCIEDAD",
"economic_activity": "VENTA AL POR MENOR DE OTROS PRODUCTOS",
"start_date": "2015-03-01",
"address": "AV. AMAZONAS Y NACIONES UNIDAS, QUITO",
"establishments": [
{
"commercial_name": "EJEMPLO",
"establishment_number": "001",
"type": "MATRIZ",
"address": "AV. AMAZONAS Y NACIONES UNIDAS, QUITO",
"status": "ABIERTO",
"is_headquarters": true
}
],
"fetched_at": "2026-06-20T16:00:00Z"
},
"error": null,
"message": null
}Cómo leer la respuesta JSON
- data.id contiene el RUC consultado.
- data.business_name y data.trade_name identifican la razón social y el nombre comercial disponible.
- data.status y data.taxpayer_type describen el estado y el tipo de contribuyente reportados.
- data.economic_activity resume la actividad principal registrada.
- data.establishments es una lista; comprueba is_headquarters para distinguir la matriz cuando esté disponible.
Errores y decisiones de negocio
- 400: el RUC no cumple el formato esperado.
- 401, 402 o 403: revisa autenticación, saldo y verificación de la cuenta según el mensaje.
- 404: no se encontraron datos para el RUC enviado; permite corregirlo y volver a intentar.
- 429: espera el tiempo indicado en Retry-After.
- 502 o 503: muestra un estado temporal y reintenta con espera progresiva; no bloquees permanentemente al proveedor o cliente.
Checklist para facturación y proveedores
- Compara el RUC devuelto con el valor enviado.
- Presenta la razón social para que el usuario confirme antes de guardar.
- No conviertas un estado aislado en una decisión automática sin las reglas de tu negocio.
- Revisa el precio vigente del endpoint y registra métricas sin incluir el RUC ni la respuesta completa.
Preguntas frecuentes
Respuestas rápidas sobre esta guía.