Obtener CSD Activo
Obtén la información del Certificado de Sello Digital (CSD) activo de una sucursal.
Endpoint
GET https://api.lummy.io/v1/branches/{id}/csd
| Entorno | URL |
|---|---|
| Producción | https://api.lummy.io/v1/branches/{id}/csd |
| Sandbox | https://sandbox.lummy.io/v1/branches/{id}/csd |
Este endpoint NO retorna los archivos .cer ni .key ni la contraseña por razones de seguridad. Solo retorna metadata del certificado.
Path Parameters
Headers
Ejemplos de Código
- cURL
- Node.js (TypeScript)
- Python
- PHP (Guzzle)
curl -X GET "https://sandbox.lummy.io/branches/550e8400-e29b-41d4-a716-446655440001/csd" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "x-organization-id: ${LUMMY_ORG_ID}"
import axios from 'axios';
interface CsdInfo {
id: string;
certificateNumber: string;
validFrom: string;
validUntil: string;
rfc: string;
isActive: boolean;
createdAt: string;
}
async function obtenerCsd(
organizationId: string,
branchId: string
): Promise<CsdInfo> {
const API_URL = `https://sandbox.lummy.io/branches/${branchId}/csd`;
const ACCESS_TOKEN = process.env.ACCESS_TOKEN!;
try {
const response = await axios.get<CsdInfo>(API_URL, {
headers: {
'Authorization': `Bearer ${ACCESS_TOKEN}`,
'x-organization-id': organizationId,
},
});
console.log('CSD activo encontrado:');
console.log(`Número de certificado: ${response.data.certificateNumber}`);
console.log(`RFC: ${response.data.rfc}`);
console.log(`Válido desde: ${response.data.validFrom}`);
console.log(`Válido hasta: ${response.data.validUntil}`);
// Verificar si está próximo a vencer
const validUntil = new Date(response.data.validUntil);
const now = new Date();
const daysLeft = Math.floor((validUntil.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
if (daysLeft < 30) {
console.warn(`El certificado expira en ${daysLeft} dias`);
}
return response.data;
} catch (error) {
console.error('Error al obtener CSD:', error);
throw error;
}
}
// Ejecutar
obtenerCsd(
'550e8400-e29b-41d4-a716-446655440000',
'550e8400-e29b-41d4-a716-446655440001'
);
npm install axios
import os
import requests
from datetime import datetime
def obtener_csd(organization_id: str, branch_id: str):
api_url = f"https://sandbox.lummy.io/branches/{branch_id}/csd"
access_token = os.getenv("ACCESS_TOKEN")
if not access_token:
raise ValueError("Debes definir ACCESS_TOKEN")
headers = {
"Authorization": f"Bearer {access_token}",
"x-organization-id": organization_id
}
try:
response = requests.get(api_url, headers=headers, timeout=30)
response.raise_for_status()
csd = response.json()
print("CSD activo encontrado:")
print(f"Número de certificado: {csd['certificateNumber']}")
print(f"RFC: {csd['rfc']}")
print(f"Válido desde: {csd['validFrom']}")
print(f"Válido hasta: {csd['validUntil']}")
# Verificar si está próximo a vencer
valid_until = datetime.fromisoformat(csd['validUntil'].replace('Z', '+00:00'))
now = datetime.now(valid_until.tzinfo)
days_left = (valid_until - now).days
if days_left < 30:
print(f"El certificado expira en {days_left} dias")
return csd
except requests.exceptions.RequestException as e:
print(f"Error al obtener CSD: {e}")
if e.response:
print(f"Detalle: {e.response.text}")
raise
if __name__ == "__main__":
obtener_csd(
'550e8400-e29b-41d4-a716-446655440000',
'550e8400-e29b-41d4-a716-446655440001'
)
pip install requests
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
function obtenerCsd(string $organizationId, string $branchId)
{
$apiUrl = "https://sandbox.lummy.io/branches/{$branchId}/csd";
$accessToken = getenv('ACCESS_TOKEN');
if (!$accessToken) {
throw new Exception('Debes definir ACCESS_TOKEN');
}
$client = new Client(['timeout' => 30]);
try {
$response = $client->get($apiUrl, [
'headers' => [
'Authorization' => 'Bearer ' . $accessToken,
'x-organization-id' => $organizationId
]
]);
$csd = json_decode($response->getBody(), true);
echo "CSD activo encontrado:\n";
echo "Número de certificado: {$csd['certificateNumber']}\n";
echo "RFC: {$csd['rfc']}\n";
echo "Válido desde: {$csd['validFrom']}\n";
echo "Válido hasta: {$csd['validUntil']}\n";
// Verificar si está próximo a vencer
$validUntil = new DateTime($csd['validUntil']);
$now = new DateTime();
$daysLeft = $now->diff($validUntil)->days;
if ($daysLeft < 30) {
echo "El certificado expira en {$daysLeft} dias\n";
}
return $csd;
} catch (RequestException $e) {
echo "Error al obtener CSD: " . $e->getMessage() . "\n";
if ($e->getResponse()) {
echo "Detalle: " . $e->getResponse()->getBody() . "\n";
}
throw $e;
}
}
try {
obtenerCsd(
'550e8400-e29b-41d4-a716-446655440000',
'550e8400-e29b-41d4-a716-446655440001'
);
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
exit(1);
}
composer require guzzlehttp/guzzle
Respuestas
Todas las respuestas siguen el formato estándar StandardResponse.
200 OK
CSD activo obtenido exitosamente.
{
"requestId": "abc123-def456",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440002",
"certificateNumber": "30001000000400002435",
"validFrom": "2024-01-01T00:00:00.000Z",
"validUntil": "2028-01-01T23:59:59.000Z",
"rfc": "XAXX010101000",
"isActive": true,
"createdAt": "2025-01-15T10:30:00.000Z"
},
"timestamp": "2025-01-15T10:30:00.000Z",
"path": "/branches/550e8400-e29b-41d4-a716-446655440001/csd",
"method": "GET"
}
404 Not Found
No se encontró un CSD activo para esta sucursal.
{
"requestId": "abc123-def456",
"error": {
"message": "No active CSD found for branch",
"code": "NotFoundException",
"status": 404
},
"timestamp": "2025-01-15T10:30:00.000Z",
"path": "/branches/550e8400-e29b-41d4-a716-446655440001/csd",
"method": "GET"
}
Si recibes un 404, significa que aún no has subido un CSD para esta sucursal. Usa el endpoint Subir CSD para cargar uno.
400 Bad Request
Falta el header x-organization-id.
{
"requestId": "abc123-def456",
"error": {
"message": "Header requerido: x-organization-id. El contexto organizacional es obligatorio.",
"code": "ValidationError",
"status": 400
},
"timestamp": "2025-01-15T10:30:00.000Z",
"path": "/branches/550e8400-e29b-41d4-a716-446655440001/csd",
"method": "GET"
}
401 Unauthorized
Token inválido o expirado.
{
"requestId": "abc123-def456",
"error": {
"message": "Unauthorized",
"code": "UnauthorizedException",
"status": 401
},
"timestamp": "2025-01-15T10:30:00.000Z",
"path": "/branches/550e8400-e29b-41d4-a716-446655440001/csd",
"method": "GET"
}
403 Forbidden
No tienes acceso a la organización especificada.
{
"requestId": "abc123-def456",
"error": {
"message": "Usuario no autorizado para la organización: 550e8400-e29b-41d4-a716-446655440000.",
"code": "ForbiddenException",
"status": 403
},
"timestamp": "2025-01-15T10:30:00.000Z",
"path": "/branches/550e8400-e29b-41d4-a716-446655440001/csd",
"method": "GET"
}
Casos de Uso
Validar Vigencia del Certificado
Usa este endpoint para verificar que el CSD siga vigente antes de emitir facturas:
const csd = await obtenerCsd(orgId, branchId);
const validUntil = new Date(csd.validUntil);
const now = new Date();
if (validUntil < now) {
console.error('El certificado ha expirado. Debes renovarlo.');
} else if ((validUntil.getTime() - now.getTime()) / (1000 * 60 * 60 * 24) < 30) {
console.warn('El certificado expira pronto. Considera renovarlo.');
}
Verificar RFC Correcto
Asegúrate de que el RFC del certificado coincide con el RFC de tu organización:
const org = await obtenerOrganizacion(orgId);
const csd = await obtenerCsd(orgId, branchId);
if (org.rfc !== csd.rfc) {
console.error('El RFC del certificado no coincide con el de la organizacion');
}