Saltearse al contenido

Envía la representación impresa de un CFE por correo

POST
/v1/cfe/enviar-email/{id}

Envía la representación impresa (PDF) de un CFE ya emitido a una lista de hasta 10 destinatarios.

Validación previa

Antes de intentar cualquier envío, Host Factura valida que todos los correos tengan un formato válido. Si alguno es inválido, se rechaza la solicitud completa con 422 (ningún correo se envía).

Reporte por destinatario

El envío se hace destinatario por destinatario: el rechazo del servidor de correo en una dirección no aborta las demás. La respuesta siempre incluye el detalle por correo en resultados[], indicando cuáles fueron exitosos (exito: true) y cuáles fallaron (exito: false) con el motivo en error.

Códigos de estado HTTP

EstadoSignificado
200Todos los correos fueron aceptados por el servidor (data.todosExitosos: true).
207Envío parcial: algunos aceptados, otros rechazados. Revisá data.resultados.
502El servidor de correo rechazó todos los envíos. El detalle va en error.details.

Exige cfe:emitir y no cfe:leer: es una comunicación saliente en nombre de la empresa, no una lectura.

Alcance requerido: cfe:emitir. Si la credencial no lo tiene, la respuesta es 403 API_ALCANCE_INSUFICIENTE con la lista en error.requerido. Las credenciales creadas antes del modelo de alcances (alcances: null) conservan acceso total.

id
required

Identificador único del recurso (UUID v4)

string format: uuid

Identificador único del recurso (UUID v4)

x-cuenta-id
string format: uuid
Ejemplo
0199d1b0-0000-7000-8000-000000000000

Sólo para credenciales de cuenta proveedora (revendedor). UUID de la subcuenta de la cartera sobre la que se quiere operar: la cuenta efectiva del request pasa a ser esa.

Una credencial que no es de proveedor, o una subcuenta que no está en su cartera, recibe 403 API_CUENTA_FUERA_DE_CARTERA. Sin la cabecera, la cuenta es siempre la de la credencial.

x-branch-id
string format: uuid

Sucursal contra la que operar, cuando la credencial es global. Si la credencial está fijada a una sucursal y esta cabecera indica otra, la respuesta es 403 API_ACCESS_BRANCH_MISMATCH. Sin la cabecera se asume la casa central.

x-point-id
string format: uuid

Punto de emisión dentro de la sucursal resuelta. Obligatorio cuando la sucursal tiene 2 o más puntos activos (400 PUNTO_EMISION_REQUERIDO si falta); con uno solo se selecciona automáticamente.

Lista de hasta 10 correos a los que enviar la representación impresa

object
correos
required
Array<string>
>= 1 items <= 10 items
Ejemplos

Reenviar a tres destinatarios

{
"correos": [
"cliente@empresa.com.uy",
"contador@empresa.com.uy",
"archivo@empresa.com.uy"
]
}

Todos los destinatarios recibieron el comprobante

object
Ejemplos

Todos los correos fueron aceptados

{
"data": {
"total": 3,
"exitosos": 3,
"fallidos": 0,
"todosExitosos": true,
"ningunoExitoso": false,
"resultados": [
{
"email": "cliente@empresa.com.uy",
"exito": true
},
{
"email": "contador@empresa.com.uy",
"exito": true
},
{
"email": "archivo@empresa.com.uy",
"exito": true
}
]
}
}

Envío parcial. Algunos correos fueron aceptados y otros rechazados. Inspeccioná data.resultados para ver el detalle por destinatario.

object
Ejemplos

Envío parcial (207): algunos aceptados, otros rechazados

{
"data": {
"total": 3,
"exitosos": 2,
"fallidos": 1,
"todosExitosos": false,
"ningunoExitoso": false,
"resultados": [
{
"email": "cliente@empresa.com.uy",
"exito": true
},
{
"email": "contador@empresa.com.uy",
"exito": true
},
{
"email": "buzon-inexistente@empresa.com.uy",
"exito": false,
"error": "Message failed: 550 5.1.1 The email account that you tried to reach does not exist — código SMTP 550"
}
]
}
}

No autenticado. La API_KEY no fue enviada, no es válida o la credencial está desactivada.

Códigos posibles: API_AUTH_HEADER_MISSING, API_AUTH_HEADER_INVALID, API_ACCESS_INVALID.

object
error
required
object
code
required

Identificador estable del error en SCREAMING_SNAKE_CASE

string
message
required

Mensaje legible en español. No parsearlo: puede cambiar

string
details
Any of:
object
requerido

Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación

Array<string>
Allowed values: cfe:emitir cfe:leer recibidos:leer consultas clientes:leer clientes:escribir pagos:leer pagos:cobrar pagos:tarjetas pagos:suscripciones pagos:configurar webhooks:gestionar
requestId

UUID de correlación; mismo valor que el header X-Request-ID

string format: uuid
Ejemplos

Falta header Authorization

{
"error": {
"code": "API_AUTH_HEADER_MISSING",
"message": "Se esperaba la cabecera Authorization con esquema Bearer"
},
"requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"
}

Acceso prohibido. La credencial es válida pero algo del contexto lo impide. Las cinco causas se corrigen de forma distinta y ninguna se arregla reintentando:

CodeQué pasóCómo se corrige
API_FEATURE_DISABLEDLa cuenta no tiene la API habilitada en su planPedir la habilitación a soporte o al proveedor
API_ALCANCE_INSUFICIENTELa credencial no tiene el alcance de la operación (va en error.requerido)Editar la credencial en Integraciones → API
API_ALCANCE_NO_DISPONIBLELa credencial tiene el alcance pero la cuenta no lo admite: sin cobros habilitados (pagos:*), sin facturación (cfe:*) o no es cuenta proveedora (webhooks:gestionar). Va en error.detailsPedir la habilitación a soporte o al proveedor
API_ACCESS_BRANCH_MISMATCHx-branch-id distinto de la sucursal fijada en la credencialQuitar la cabecera o usar otra credencial
API_CUENTA_FUERA_DE_CARTERAx-cuenta-id apunta a una cuenta que no es de la carteraRevisar el UUID de la subcuenta
object
error
required
object
code
required

Identificador estable del error en SCREAMING_SNAKE_CASE

string
message
required

Mensaje legible en español. No parsearlo: puede cambiar

string
details
Any of:
object
requerido

Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación

Array<string>
Allowed values: cfe:emitir cfe:leer recibidos:leer consultas clientes:leer clientes:escribir pagos:leer pagos:cobrar pagos:tarjetas pagos:suscripciones pagos:configurar webhooks:gestionar
requestId

UUID de correlación; mismo valor que el header X-Request-ID

string format: uuid
Ejemplos

Falta el alcance

{
"error": {
"code": "API_ALCANCE_INSUFICIENTE",
"message": "La credencial de API no tiene ninguno de los alcances necesarios para esta operación (pagos:cobrar)",
"requerido": [
"pagos:cobrar"
]
},
"requestId": "3f6b1c2e-9a4d-4f80-bc11-7e2d5a8f0c31"
}

CFE no encontrado o pertenece a otra cuenta

object
error
required
object
code
required

Identificador estable del error en SCREAMING_SNAKE_CASE

string
message
required

Mensaje legible en español. No parsearlo: puede cambiar

string
details
Any of:
object
requerido

Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación

Array<string>
Allowed values: cfe:emitir cfe:leer recibidos:leer consultas clientes:leer clientes:escribir pagos:leer pagos:cobrar pagos:tarjetas pagos:suscripciones pagos:configurar webhooks:gestionar
requestId

UUID de correlación; mismo valor que el header X-Request-ID

string format: uuid
Ejemplos

CFE no encontrado

{
"error": {
"code": "CFE_EMITIDO_NO_ENCONTRADO",
"message": "CFE no encontrado (uuid)"
},
"requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"
}

Rate limit excedido. Esperá los segundos del header Retry-After. La cuota va por credencial: 60 req/min en cuentas estándar, 600 en cuentas proveedor.

object
error
required
object
code
required

Identificador estable del error en SCREAMING_SNAKE_CASE

string
message
required

Mensaje legible en español. No parsearlo: puede cambiar

string
details
Any of:
object
requerido

Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación

Array<string>
Allowed values: cfe:emitir cfe:leer recibidos:leer consultas clientes:leer clientes:escribir pagos:leer pagos:cobrar pagos:tarjetas pagos:suscripciones pagos:configurar webhooks:gestionar
requestId

UUID de correlación; mismo valor que el header X-Request-ID

string format: uuid
Ejemplos

Excediste el rate limit

{
"error": {
"code": "API_RATE_LIMITED",
"message": "Se superó el límite de requests para esta API key"
},
"requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"
}
Retry-After
integer
Ejemplo
42

Segundos hasta que se libera la ventana de rate limit

El servidor de correo rechazó todos los envíos. El detalle por destinatario (con el motivo de cada rechazo) viene en error.details.

object
error
required
object
code
required

Identificador estable del error en SCREAMING_SNAKE_CASE

string
message
required

Mensaje legible en español. No parsearlo: puede cambiar

string
details
Any of:
object
requerido

Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación

Array<string>
Allowed values: cfe:emitir cfe:leer recibidos:leer consultas clientes:leer clientes:escribir pagos:leer pagos:cobrar pagos:tarjetas pagos:suscripciones pagos:configurar webhooks:gestionar
requestId

UUID de correlación; mismo valor que el header X-Request-ID

string format: uuid
Ejemplos

El servidor de correo rechazó todos los envíos

{
"error": {
"code": "EMAIL_ENVIO_FALLIDO",
"message": "El servidor de correo rechazó el envío a todos los destinatarios",
"details": {
"total": 2,
"exitosos": 0,
"fallidos": 2,
"todosExitosos": false,
"ningunoExitoso": true,
"resultados": [
{
"email": "no-existe@empresa.com.uy",
"exito": false,
"error": "Message failed: 550 5.1.1 The email account that you tried to reach does not exist — código SMTP 550"
},
{
"email": "dominio-caido@empresa.com.uy",
"exito": false,
"error": "getaddrinfo ENOTFOUND mail.dominio-caido.com — código ENOTFOUND"
}
]
}
},
"requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"
}