Quién firma
Elige si firmamos nosotros o el XML llega ya firmado desde el sistema de la empresa.
Autenticación: token Bearer de cuenta (empresas:manage).
Consideraciones
provider(por defecto): firmamos con nuestro certificado de PSE. Cada emisión consume una firma del plan.external: el XML llega ya firmado y solo lo transportamos. No consume firmas ni plataforma; por eso exigedestination: provider_ose, lo único que entonces consume la empresa. Con otro destino responde422.- El certificado propio (
own_certificateen la respuesta) no se elige aquí: se carga con POST /v1/companies/{ruc}/certificate y la firma pasa a consumir menos. - Con firma externa no hay PSE que autorizar ante SUNAT:
sunat_procedures.psevienenull.
Las tres formas de firmar
signing |
Qué es | Qué consume |
|---|---|---|
provider |
Por defecto. Firmamos nosotros como PSE. | Una firma del plan por comprobante |
own_certificate |
La empresa subió su certificado y firma con su identidad. | Menos que una firma completa: sigue usando la plataforma |
external |
El XML llega ya firmado desde el sistema de la empresa. | Solo el paquete de envíos por nuestro OSE |
Este endpoint alterna entre provider y external. El certificado propio se
activa solo: al cargarlo, la respuesta pasa
a decir own_certificate.
Por qué la firma externa exige nuestro OSE
Quien firma fuera no consume plataforma ni firmas del PSE: de nosotros usa
solo la salida. Si además saliera directo a SUNAT o por su propio OSE, no
quedaría nada que cobrar — no sería una combinación barata, sería gratis. Por eso
external solo se acepta con destination: provider_ose, y el orden importa:
primero el destino, luego la firma.
Cómo se emite con firma externa
El comprobante se manda firmado, por el proxy SOAP compatible con SUNAT
(/ol-ti-itcpe/billService) con las credenciales de la empresa. No pasa por
POST /v1/cpe, que es quien firma.
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 11 dígitos de la empresa. |
Body
| Name | Type | Description |
|---|---|---|
| signing* | string | provider (por defecto) · external. |
Ejemplo de solicitud
curl -X PATCH https://api.xmlperu.dev/v1/companies/20123456789/signing \
-H "Authorization: Bearer $TOKEN_CUENTA" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"signing": "external"
}'<?php
$token_cuenta = 'pega-aqui-tu-token';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.xmlperu.dev/v1/companies/20123456789/signing');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer ' . $token_cuenta,
'Accept: application/json',
'Content-Type: application/json',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, <<<JSON
{
"signing": "external"
}
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/signing', {
method: 'PATCH',
headers: {
Authorization: `Bearer ${TOKEN_CUENTA}`,
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"signing": "external"
}),
});
const data = await res.json();import requests
TOKEN_CUENTA = "pega-aqui-tu-token"
headers = {
"Authorization": f"Bearer {TOKEN_CUENTA}",
"Accept": "application/json",
}
payload = {
"signing": "external"
}
res = requests.patch("https://api.xmlperu.dev/v1/companies/20123456789/signing", json=payload, headers=headers)
data = res.json()Respuesta
{
"success": true,
"message": "Firma actualizada.",
"data": {
"company": {
"ruc": "20123456789",
"business_name": "MI EMPRESA SAC",
"plan_type": "01",
"environment": "02",
"environment_name": "production",
"destination": "provider_ose",
"signing": "external",
"sol_credentials": false,
"sunat_procedures": { "pse": null, "ose": "not_started" },
"is_active": true
}
}
}provider_ose. Cambia primero el destino.{
"success": false,
"message": "La firma en el sistema del cliente (signing: external) solo está disponible enviando por nuestro OSE (destination: provider_ose): es lo único que entonces consume la empresa."
}