Crear Carta Porte
Este endpoint permite crear y sellar un CFDI de Traslado con el complemento Carta Porte v3.1.
- Método HTTP:
POST - URL:
/invoices
Cabeceras
"application/json"*Debes usar uno de los dos métodos de autenticación: Authorization (Bearer JWT) o x-api-key.
Este endpoint tiene un límite de 30 solicitudes por minuto por organización.
Estructura del Request
El cuerpo de la petición es un objeto JSON que representa el CrearComprobanteDto.
Objeto Principal: CrearComprobanteDto
"T"Objeto: ReceptorDto
Objeto: ConceptoDto
Objeto Principal: ComplementoCartaPorteDto
"Sí""No"Objeto: UbicacionDto
"Origen""Destino""Intermedio"Objeto: DomicilioDto
Objeto: MercanciaDto
"Sí""No"Objeto: IdentificacionVehicularDto
Objeto: SegurosDto
Objeto: TiposFiguraDto
Ejemplos de Código
- cURL
- Python
curl -X POST https://sandbox.lummy.io/invoices \
-H "Content-Type: application/json" \
-H "x-organization-id: ${LUMMY_ORG_ID}" \
-H "x-api-key: ${LUMMY_API_KEY}" \
-H "x-idempotency: $(uuidgen)" \
-d '{
"tipoDeComprobante": "T",
"receptor": {
"rfc": "XAXX010101000",
"nombre": "Receptor de Prueba",
"regimenFiscal": "601",
"domicilioFiscal": "12345",
"email": "receptor@ejemplo.com"
},
"conceptos": [
{
"claveProdServ": "84111506",
"cantidad": 1,
"claveUnidad": "E48",
"descripcion": "Servicio de transporte de mercancías",
"valorUnitario": 0,
"objetoImp": "01"
}
],
"moneda": "MXN",
"exportacion": "01",
"lugarExpedicion": "06500",
"fecha": "2025-01-15T12:00:00",
"complementoCartaPorte": {
"transpInternac": "No",
"totalDistRec": 150.5,
"ubicaciones": [
{
"tipoUbicacion": "Origen",
"rfcRemitenteDestinatario": "AAA010101AAA",
"fechaHoraSalidaLlegada": "2025-01-15T08:00:00",
"domicilio": {
"municipio": "015",
"estado": "CMX",
"pais": "MEX",
"codigoPostal": "03900"
}
},
{
"tipoUbicacion": "Destino",
"rfcRemitenteDestinatario": "BBB020202BBB",
"fechaHoraSalidaLlegada": "2025-01-15T12:00:00",
"distanciaRecorrida": 150.5,
"domicilio": {
"municipio": "002",
"estado": "JAL",
"pais": "MEX",
"codigoPostal": "44100"
}
}
],
"mercancias": [
{
"bienesTransp": "10101504",
"cantidad": 1000,
"claveUnidad": "KGM",
"pesoEnKg": 1500
}
],
"permSCT": "TPAF01",
"numPermisoSCT": "ABC123456",
"identificacionVehicular": {
"configVehicular": "T3S1",
"placaVM": "XYZ-789",
"anioModeloVM": 2020
},
"seguros": {
"aseguraRespCivil": "Seguros Atlas S.A.",
"polizaRespCivil": "POL-123456"
},
"figuraTransporte": [
{
"tipoFigura": "01",
"rfcFigura": "AAAA010101AAA",
"numLicencia": "A1234567"
}
]
}
}'
import os
import requests
import uuid
headers = {
'Content-Type': 'application/json',
'x-organization-id': os.environ.get('LUMMY_ORG_ID'),
'x-api-key': os.environ.get('LUMMY_API_KEY'),
'x-idempotency': str(uuid.uuid4()),
}
json_data = {
'tipoDeComprobante': 'T',
'receptor': {
'rfc': 'XAXX010101000',
'nombre': 'Receptor de Prueba',
'regimenFiscal': '601',
'domicilioFiscal': '12345',
'email': 'receptor@ejemplo.com',
},
'conceptos': [
{
'claveProdServ': '84111506',
'cantidad': 1,
'claveUnidad': 'E48',
'descripcion': 'Servicio de transporte de mercancías',
'valorUnitario': 0,
'objetoImp': '01',
},
],
'moneda': 'MXN',
'exportacion': '01',
'lugarExpedicion': '06500',
'fecha': '2025-01-15T12:00:00',
'complementoCartaPorte': {
'transpInternac': 'No',
'totalDistRec': 150.5,
'ubicaciones': [
{
'tipoUbicacion': 'Origen',
'rfcRemitenteDestinatario': 'AAA010101AAA',
'fechaHoraSalidaLlegada': '2025-01-15T08:00:00',
'domicilio': {
'municipio': '015',
'estado': 'CMX',
'pais': 'MEX',
'codigoPostal': '03900',
},
},
{
'tipoUbicacion': 'Destino',
'rfcRemitenteDestinatario': 'BBB020202BBB',
'fechaHoraSalidaLlegada': '2025-01-15T12:00:00',
'distanciaRecorrida': 150.5,
'domicilio': {
'municipio': '002',
'estado': 'JAL',
'pais': 'MEX',
'codigoPostal': '44100',
},
},
],
'mercancias': [
{
'bienesTransp': '10101504',
'cantidad': 1000,
'claveUnidad': 'KGM',
'pesoEnKg': 1500,
},
],
'permSCT': 'TPAF01',
'numPermisoSCT': 'ABC123456',
'identificacionVehicular': {
'configVehicular': 'T3S1',
'placaVM': 'XYZ-789',
'anioModeloVM': 2020,
},
'seguros': {
'aseguraRespCivil': 'Seguros Atlas S.A.',
'polizaRespCivil': 'POL-123456',
},
'figuraTransporte': [
{
'tipoFigura': '01',
'rfcFigura': 'AAAA010101AAA',
'numLicencia': 'A1234567',
},
],
},
}
response = requests.post('https://sandbox.lummy.io/invoices', headers=headers, json=json_data)
print(response.json())
Respuesta Exitosa (HTTP 201 Created)
Todas las respuestas siguen el formato estándar StandardResponse:
{
"requestId": "abc123-def456",
"data": {
"invoiceId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"cfdiUuid": "cfa52b8b-93f2-4e6b-8c73-64ad88deb17c",
"verificationUrl": "https://verificacfdi.facturaelectronica.sat.gob.mx/default.aspx?id=cfa52b8b-93f2-4e6b-8c73-64ad88deb17c",
"xmlUrl": "https://lummy-invoices.s3.amazonaws.com/cfdi/cfa52b8b-93f2-4e6b-8c73-64ad88deb17c.xml",
"status": "stamped"
},
"timestamp": "2025-01-20T10:00:00.000Z",
"path": "/invoices",
"method": "POST"
}
| Campo | Tipo | Descripción |
|---|---|---|
requestId | string | ID único de la solicitud para trazabilidad |
data.invoiceId | string (UUID) | ID interno de la factura en Lummy |
data.cfdiUuid | string (UUID) | UUID fiscal del SAT - Folio fiscal del CFDI timbrado |
data.verificationUrl | string (URL) | URL para verificar el CFDI en el portal del SAT |
data.xmlUrl | string (URL) | URL pública para descargar el XML timbrado |
data.status | string | Estado del timbrado: stamped o pending_stamping |
timestamp | string (ISO) | Fecha y hora de la respuesta |
path | string | Ruta del endpoint |
method | string | Método HTTP de la solicitud |
El archivo PDF se genera de forma asíncrona después del timbrado y se envía automáticamente por correo electrónico al receptor.
Respuesta Pendiente de Timbrado (HTTP 201 Created)
Si el PAC no responde o hay un error temporal, la factura se guarda y se reintenta automáticamente:
{
"requestId": "abc123-def456",
"data": {
"invoiceId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"cfdiUuid": "",
"verificationUrl": "",
"xmlUrl": "",
"status": "pending_stamping",
"retryInfo": {
"nextRetryAt": "2025-01-20T10:05:00.000Z",
"attempt": 1,
"maxAttempts": 5
}
},
"timestamp": "2025-01-20T10:00:00.000Z",
"path": "/invoices",
"method": "POST"
}
| Campo | Tipo | Descripción |
|---|---|---|
data.status | string | pending_stamping indica que el timbrado está en cola |
data.retryInfo.nextRetryAt | string (ISO) | Fecha y hora del próximo reintento automático |
data.retryInfo.attempt | number | Número de intento actual |
data.retryInfo.maxAttempts | number | Número máximo de reintentos (5) |
El sistema reintenta automáticamente el timbrado con backoff exponencial. Puedes consultar el estado con GET /invoices/{invoiceId}.
Respuestas de Error
Todas las respuestas de error siguen el formato estándar StandardResponse:
{
"requestId": "abc123-def456",
"error": {
"message": "Descripción del error",
"code": "ERROR_CODE",
"status": 400
},
"timestamp": "2025-01-20T10:00:00.000Z",
"path": "/invoices",
"method": "POST"
}
| Código | Descripción |
|---|---|
| 400 | Datos de entrada inválidos (ubicaciones, mercancías, vehículo, etc.) |
| 401 | Token de autenticación inválido o expirado |
| 403 | Sin permisos (suscripción inactiva, scope insuficiente) |
| 404 | Sucursal o CSD no encontrado |
| 409 | Clave de idempotencia ya usada |
| 422 | Rechazo del PAC/SAT (datos de carta porte inválidos) |
| 429 | Rate limit excedido (máximo 30 solicitudes por minuto) |
| 500 | Error interno del servidor |
Errores Comunes de Carta Porte
| Error SAT | Descripción |
|---|---|
CCP30101 | Falta nodo de ubicación origen o destino |
CCP30102 | Distancia recorrida no válida |
CCP30103 | RFC del remitente/destinatario inválido |
CCP30104 | Permiso SCT no válido para el tipo de transporte |
CCP30105 | Configuración vehicular incompatible con el peso |
CCP30106 | Falta número de licencia para el operador |
CCP30107 | Material peligroso requiere clave de embalaje |