Certificado propio
Registra el certificado digital de la empresa para firmar con él en vez del nuestro. Cada emisión consume menos plan.
Autenticación: token Bearer de cuenta (empresas:manage).
Consideraciones
- Con certificado propio, la empresa firma con su identidad y cada emisión consume 0,67 firmas en vez de 1: no se paga nuestra firma, pero sí el uso de la plataforma. El paquete rinde alrededor de un 49 % más.
- El
.pfxse convierte a PEM y la contraseña se descarta: no se guarda en ninguna parte. Un PEM sin contraseña ya firma solo, así que custodiarla además no protegería nada. - El certificado debe corresponder al RUC de la empresa. Si el RUC del certificado no coincide, se rechaza — nadie puede firmar en nombre de otro.
- El archivo nunca se devuelve. No hay endpoint de descarga: solo lo abre el firmador.
GETdevuelve la metadata (titular, vigencia, huella) para que compruebes que subiste el correcto. - Si el certificado vence, la emisión no se bloquea: se vuelve automáticamente al certificado del proveedor mientras renuevas —consumiendo la firma entera, eso sí—.
DELETElo retira y borra el archivo; la empresa vuelve a firmar con el del proveedor y a consumir su plan.- Cada comprobante registra con qué se firmó (
pseopropio), para auditoría y facturación.
Qué cambia al usar tu certificado
Sin certificado propio, firmamos con el certificado del proveedor y cada comprobante consume una firma de tu plan.
Con certificado propio, firmas con tu identidad: el X509Certificate que
viaja dentro del XML es el tuyo. Cada emisión consume entonces 0,67 firmas en
vez de 1: dejas de pagar nuestra firma, pero no el resto del trabajo, que es el
mismo —armar el comprobante, validarlo, gestionar el
envío, reintentar lo que falle y perseguir el CDR—.
En la práctica el paquete rinde alrededor de un 49 % más: donde caben 2.000 comprobantes firmados por nosotros, caben unos 2.985 firmados por ti.
| Firma nuestra | Tu certificado | |
|---|---|---|
| Consume por emisión | 1 firma | 0,67 firmas |
| Paquete de 2.000 alcanza para | 2.000 | ~2.985 |
El consumo se descuenta en centésimas, así que no se pierde nada por redondeo.
Los tres endpoints
# Registrar (multipart)
curl -X POST https://api.xmlperu.dev/v1/companies/$RUC/certificate \
-H "Authorization: Bearer $TOKEN_CUENTA" \
-F "certificado=@mi-certificado.pfx" \
-F "password=mi-clave"
# Ver la metadata (nunca el archivo)
curl https://api.xmlperu.dev/v1/companies/$RUC/certificate \
-H "Authorization: Bearer $TOKEN_CUENTA"
# Retirar
curl -X DELETE https://api.xmlperu.dev/v1/companies/$RUC/certificate \
-H "Authorization: Bearer $TOKEN_CUENTA"
Qué hacemos con tu certificado
Es tu identidad fiscal: quien lo tiene puede firmar en tu nombre. Por eso:
- La contraseña no se guarda. Se usa una vez para abrir el
.pfx, se convierte a PEM y se descarta. - El archivo no sale de aquí. No existe forma de descargarlo por la API ni por el panel; solo lo abre el proceso de firma.
- Se borra cuando lo retiras, y al eliminar la empresa.
- Cada uso queda registrado: el comprobante guarda si se firmó con el certificado propio o con el del proveedor.
Si vence
La emisión no se detiene. Al detectar que el certificado venció, volvemos al
del proveedor automáticamente y el comprobante sale igual — consumiendo plan, eso sí.
Consulta vigente_hasta con el GET para renovarlo antes de que ocurra.
Headers
| Name | Type | Description |
|---|---|---|
| Accept | string | application/json |
| Content-Type | string | application/json |
| Authorization | string | Bearer <token>. Genéralo desde tu panel, en Tokens de API. |
Parámetros de URL
| Name | Type | Description |
|---|---|---|
| ruc* | string | RUC de la empresa (11 dígitos). |
Body
| Name | Type | Description |
|---|---|---|
| certificate* | file | Archivo `.pfx`/`.p12` (o `.pem` con la clave privada). Máximo 5 MB. Enviar como `multipart/form-data`. |
| password | string | Contraseña del `.pfx`. Se usa una sola vez para abrirlo y no se guarda. |
Ejemplo de solicitud
curl -X POST https://api.xmlperu.dev/v1/companies/20123456789/certificate \
-H "Authorization: Bearer $TOKEN_CUENTA" \
-H "Accept: application/json"<?php
$token_cuenta = 'pega-aqui-tu-token';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.xmlperu.dev/v1/companies/20123456789/certificate');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token_cuenta,
'Accept: application/json',
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);const TOKEN_CUENTA = 'pega-aqui-tu-token';
const res = await fetch('https://api.xmlperu.dev/v1/companies/20123456789/certificate', {
method: 'POST',
headers: {
Authorization: `Bearer ${TOKEN_CUENTA}`,
Accept: 'application/json',
},
});
const data = await res.json();import requests
TOKEN_CUENTA = "pega-aqui-tu-token"
headers = {
"Authorization": f"Bearer {TOKEN_CUENTA}",
"Accept": "application/json",
}
res = requests.post("https://api.xmlperu.dev/v1/companies/20123456789/certificate", headers=headers)
data = res.json()Respuesta
{
"success": true,
"message": "Certificado registrado. Los próximos comprobantes se firmarán con él.",
"data": {
"certificado": {
"has_certificate": true,
"titular": "MI EMPRESA SAC",
"serie": "5A3F19E2C48B",
"huella": "3f2a9c8e…",
"vigente_desde": "2026-01-15",
"vigente_hasta": "2027-01-15",
"vigente": true
}
}
}{
"success": false,
"message": "El certificado no corresponde al RUC 20123456789. Verifica que subiste el de tu empresa."
}{
"success": false,
"message": "No se pudo abrir el certificado: la contraseña es incorrecta o el archivo no es válido."
}{
"success": false,
"message": "El certificado venció el 2026-03-01."
}