Común a los 7 sistemas — nunca cambia según tu ERP. Léela una vez; las guías por sistema solo añaden lo específico de tu lado.
Cómo funciona
proveedor_homologado · tu ERP puede responder con su código (supplier_erp)purchase_requisitionsorden_aprobadapurchase_order_erpfactura_conforme · trae tu n.º de SOLPED y el de la ordeninvoice_payment · PIZ se lo avisa al proveedorCada pieza se usa por separado. Puedes conectar solo la entrada de SOLPED (1), solo la salida de facturas (7), que tu ERP reciba a los proveedores homologados (0), que tu ERP emita las órdenes (3 y 4), o el ciclo completo con los avisos de pago (8). Lo que no conectes se hace en las pantallas de PIZ.
Todo es asíncrono. Enviar una SOLPED confirma solo que PIZ la recibió — la RFQ queda en borrador hasta que un comprador la revisa y publica.
La orden de compra: la emite PIZ o tu ERP
En PIZ se decide la compra: convocatoria, comparación de ofertas, adjudicación y firmas. Dónde nace la orden oficial lo elige el administrador en Mi organización → Integraciones API → ¿Quién emite la orden de compra?
| Opción | Qué pasa al completarse las firmas |
|---|---|
| PIZ | PIZ emite la orden con tu numeración (se configura en Mi organización → Nomenclatura de documentos) y se la envía al proveedor. Pasos 5 a 8 del gráfico. |
| Mi ERP | La orden queda «Esperando al ERP» y el proveedor todavía no la ve. PIZ le envía a tu ERP el evento orden_aprobada (paso 3). Tu ERP emite la orden y responde con POST /purchase_order_erp.php (paso 4): su número pasa a ser el oficial y, si lo envía, su PDF queda adjunto. Recién entonces el proveedor la recibe. |
Cambios y anulaciones. Si una orden se modifica, la modificación es una orden nueva: al aprobarse le llega a tu ERP como orden_aprobada con modifica_a = la orden anterior. Si una orden que ya se le pidió a tu ERP se anula, tu ERP recibe el evento orden_anulada con el motivo.
Si tu ERP no puede emitirla (falta el proveedor, un artículo o un centro de costo), responde con error y el motivo: la orden sigue esperando y el comprador lo ve en PIZ, con dos salidas: volver a pedírsela al ERP cuando esté corregido, o emitirla desde PIZ con el número de PIZ.
Recomendaciones
- La aprobación, en un solo lugar. Si las firmas se hacen en PIZ, tu ERP no debe volver a pedir la aprobación de la misma compra.
- Una sola numeración. Si tu ERP emite la orden, manda su número. Si la emite PIZ, configura en PIZ el mismo formato que usa tu organización.
- El proveedor, creado en tu ERP. Si tu ERP emite la orden, el proveedor tiene que existir en él: el evento
orden_aprobadatrae su RUC para ubicarlo. - Cruza por tus propios números. Usa
solped_numeroyoc_codigopara enlazar en tu ERP la solicitud, la orden y la factura. - Los mismos códigos de material. Homologa una vez tus códigos con las categorías de PIZ (ver Tu propio código de material).
- Cierra el ciclo. Cuando tu ERP pague la factura, avísale a PIZ con
invoice_payment: el proveedor ve su pago sin preguntar.
Autenticación
OAuth 2.0 Client Credentials — estándar, sin nada propietario que aprender.
| Dato | Valor |
|---|---|
| Token endpoint | POST /api/v1/oauth_token.php |
| Grant type | client_credentials |
| Vigencia del token | 3600 s — cachea y renueva |
| Transporte | Authorization: Bearer <token>, HTTPS obligatorio |
Scopes — qué permite pedir cada uno
Al crear tu credencial (Mi organización → Integraciones API) eliges qué scopes lleva. Pide solo los que realmente vas a usar.
| Scope | Qué permite |
|---|---|
solped:write | Enviar una SOLPED (POST /purchase_requisitions.php) — el scope que casi todos necesitan. |
status:read | Consultar el estado de una RFQ ya enviada (GET /purchase_requisitions_status.php). |
payment:write | Avisar a PIZ que una factura aprobada fue pagada (POST /invoice_payment.php). |
order:write | Responder con la orden que emitió tu ERP (POST /purchase_order_erp.php). Solo si tu ERP emite las órdenes. |
supplier:write | Responder con el código que tu ERP le dio a un proveedor homologado (POST /supplier_erp.php). |
curl -X POST https://[ambiente]/api/v1/oauth_token.php \
-H "Content-Type: application/json" \
-d '{
"grant_type": "client_credentials",
"client_id": "TU_CLIENT_ID",
"client_secret": "TU_CLIENT_SECRET"
}'
{
"access_token": "f6d3f1a1df89...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "solped:write,status:read"
}
Cómo obtener acceso
En sandbox, cualquier administrador de tu organización puede generar credenciales de inmediato desde Mi organización → Integraciones API — sin pedirlo a nadie; si todavía no tienes cuenta, contacta a tu contraparte comercial para que te creen una organización de prueba ahí. En producción, Integraciones API es un add-on que primero debe activar tu contraparte comercial para tu organización — una vez activo, la generación de credenciales es igual de inmediata desde el mismo panel.
Enviar una SOLPED
POST /api/v1/purchase_requisitions.php — crea una RFQ en PIZ en estado "borrador". Un comprador la revisa y la publica.
| Campo | Tipo | Oblig. |
|---|---|---|
solped_numero | string | sí |
titulo | string | sí |
tipo_compra | bienes·servicios | sí |
categoria_codigo | string | sí |
centro_costo | string | no |
presupuesto_referencial | decimal | no |
moneda | PEN·USD | no |
items | array de objetos | sí, si tipo_compra=bienes |
items[].codigo_erp | string, hasta 40 caracteres — el código del artículo en tu ERP (en SAP Business One, su ItemCode) | no |
Si tipo_compra es bienes, items es obligatorio — un arreglo con al menos un artículo, porque una sola SOLPED puede traer varios distintos (ej. cascos + arneses). Cada ítem: descripcion (string, obligatorio), cantidad (decimal, obligatorio, mayor a 0), unidad_medida (string, opcional), presupuesto_referencial (decimal, opcional, por ítem) y codigo_erp (string, opcional). codigo_erp es el código del artículo en tu ERP: PIZ lo guarda en el ítem y te lo devuelve en orden_aprobada y factura_conforme. El proveedor no lo ve. Si tipo_compra es servicios, items no aplica — usa descripcion como hasta ahora.
{
"solped_numero": "4500128394",
"titulo": "Compra de EPP para cuadrilla de mina",
"tipo_compra": "bienes",
"categoria_codigo": "MIN-014",
"items": [
{ "codigo_erp": "EPP-0101", "descripcion": "Casco de seguridad", "unidad_medida": "unidad", "cantidad": 10 },
{ "descripcion": "Arnés de seguridad", "unidad_medida": "unidad", "cantidad": 5, "presupuesto_referencial": 175.00 }
]
}
El header Idempotency-Key es obligatorio — un reintento con la misma key nunca duplica la RFQ.
Recibir la factura
PIZ hace POST a tu URL de callback en cuanto una factura queda con conformidad, firmado con X-PIZ-Signature (HMAC-SHA256 con tu webhook_secret). Si tu endpoint no responde 2xx, reintentamos con backoff (1 min, 5 min, 30 min, 3 h, 24 h) hasta 5 veces.
Además de la factura, el aviso trae lo necesario para registrar el ingreso al almacén (o la recepción del servicio): tipo (bien o servicio), proveedor (RUC, razón social y tu erp_codigo) y recepcion, con quién dio la conformidad, el número de guía, el de la HES y los ítems con su cantidad. Cada ítem trae su codigo_erp: el código del artículo en tu ERP, o null si no se puso.
Los avisos que recibe tu ERP
Todos llegan a tu URL de callback, firmados con X-PIZ-Signature y con reintentos. El encabezado X-PIZ-Event y el campo evento dicen cuál es. Ignora los que no uses.
| Evento | Cuándo llega |
|---|---|
proveedor_homologado | Un proveedor queda homologado (también al renovarse). Solo si activaste «Avisar a mi ERP cada proveedor homologado». |
orden_aprobada | Una orden completa sus firmas. Solo si tu ERP emite las órdenes. |
orden_anulada | Se anula una orden que ya se le había pedido a tu ERP. |
factura_conforme | Una factura recibe la conformidad del comprador. |
Dar de alta al proveedor en tu ERP
Con «Avisar a mi ERP cada proveedor homologado» activado (Mi organización → Integraciones API), tu ERP recibe al proveedor apenas queda homologado, antes de que gane una compra. Así, cuando llegue la primera orden, ya existe en tu ERP.
{
"evento": "proveedor_homologado",
"ruc": "20512345678",
"razon_social": "SUMINISTROS ANDINOS S.A.C.",
"erp_codigo": null,
"direccion_fiscal": "Av. Argentina 1234, Lima",
"telefono": "+51 1 555 0101",
"contacto": { "nombre": "Ana Torres", "email": "ana.torres@suministrosandinos.pe" },
"datos_bancarios": { "banco": "BCP", "tipo_cuenta": "corriente", "numero_cuenta": "193-1234567-0-01", "cci": "00219300123456700112", "cuenta_detracciones": "00-123-456789" },
"categorias": [ { "nombre": "Equipos de protección personal", "codigo": "SEG-004" } ],
"homologado_at": "2026-10-13T11:20:00-05:00",
"es_renovacion": false
}
Cuando lo des de alta, responde con el código que le diste (en SAP Business One, su CardCode): POST /api/v1/supplier_erp.php con { "ruc": "20512345678", "erp_codigo": "P00123" } y el scope supplier:write. Desde entonces ese código viaja en proveedor.erp_codigo de cada orden_aprobada y factura_conforme de ese proveedor.
Recibir la orden aprobada (si tu ERP emite la orden)
A la misma URL de callback, firmado igual (X-PIZ-Signature) y con los mismos reintentos. El encabezado X-PIZ-Event dice qué trae el cuerpo: orden_aprobada o factura_conforme.
{
"evento": "orden_aprobada",
"oc_codigo": "OC-2026-00124",
"solped_numero": "4500128394",
"rfq_codigo": "RFQ-0123",
"tipo": "compra",
"modifica_a": null,
"contrato_marco": null,
"proveedor": { "ruc": "20512345678", "razon_social": "SUMINISTROS ANDINOS S.A.C.", "erp_codigo": "P00123" },
"moneda": "PEN",
"monto_total": 17500.00,
"fecha_entrega": "2026-10-20",
"condiciones_pago": "Crédito 30 días",
"plazo_entrega": "5 días",
"items": [
{ "codigo_erp": "A00125", "descripcion": "Reductor 15 HP", "unidad": "Unidad", "cantidad": 1, "monto": 17500.00 }
],
"centros_costo": [ { "nombre": "Mantenimiento", "codigo": "CC-200", "porcentaje": 100 } ],
"aprobada_at": "2026-10-13T17:05:00-05:00"
}
items[].codigo_erp es el código del artículo en tu ERP (en SAP Business One, su ItemCode), el que el comprador escribió en «Código en tu sistema» o el que llegó con la SOLPED. Es opcional: si no se puso, llega null. Con él tu ERP puede crear una orden de inventario. El proveedor no lo ve.
Responder con la orden emitida por tu ERP
POST /api/v1/purchase_order_erp.php — requiere el scope order:write y el header Idempotency-Key. Envía uno de los dos: erp_numero si la emitiste, o error si no pudiste.
| Campo | Tipo | Oblig. |
|---|---|---|
oc_codigo | string — el que recibiste en orden_aprobada | sí |
erp_numero | string, hasta 40 caracteres — tu número de orden | sí, si la emitiste |
pdf_base64 | string — el PDF de tu orden, hasta 5 MB | no |
error | string — por qué no pudiste emitirla | sí, si no la emitiste |
curl -X POST https://[ambiente]/api/v1/purchase_order_erp.php \
-H "Authorization: Bearer TU_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: OC-2026-00124-emitida" \
-d '{ "oc_codigo": "OC-2026-00124", "erp_numero": "4500009871" }'
{ "oc_codigo": "4500009871", "codigo_piz": "OC-2026-00124", "estado": "aprobada", "pdf_adjunto": false }
Desde ese momento la orden se identifica con tu número: oc_codigo en la factura conforme y en invoice_payment es 4500009871. Un número que ya usa otra orden de tu organización se rechaza con 409 numero_repetido; repetir el mismo aviso responde 200 con ya_estaba_registrada: true.
Avisar el pago de una factura
POST /api/v1/invoice_payment.php — cuando tu ERP paga una factura, avísale a PIZ: la factura pasa a pagado y se notifica al proveedor. Requiere el scope payment:write. Es la contraparte entrante del webhook de conformidad: aquel te avisa a ti que la factura quedó conforme; este te deja cerrar el ciclo avisando el pago de vuelta.
Pago programado. Antes del pago puedes avisar para cuándo está programado: envía "estado": "programado" y "fecha_programada": "2026-10-30". La factura sigue aprobada, el proveedor ve «Pago programado para el 30 oct 2026» y recibe el aviso. Cuando pagues, envía el aviso normal (sin estado, o con "estado": "pagado").
Identifica la factura por su factura_codigo (el FA-XXXX que ya recibiste en el webhook) o por el par oc_codigo + numero_factura. La factura debe estar aprobada (con conformidad del comprador); solo entonces corresponde el pago.
| Campo | Tipo | Oblig. |
|---|---|---|
factura_codigo | string (FA-XXXX) | sí, si no envías el par |
oc_codigo | string (OC-XXXX) | sí, si no envías factura_codigo |
numero_factura | string | sí, junto con oc_codigo |
fecha_pago | string (ISO 8601) | no — por defecto, el momento del aviso |
curl -X POST https://[ambiente]/api/v1/invoice_payment.php \
-H "Authorization: Bearer TU_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: PAGO-FA-0231-2026-09-22" \
-d '{
"factura_codigo": "FA-0231",
"fecha_pago": "2026-09-22T15:30:00-05:00"
}'
{
"factura_codigo": "FA-0231",
"estado_pago": "pagado",
"pagado_at": "2026-09-22T15:30:00-05:00"
}
El header Idempotency-Key es obligatorio — un reintento con la misma key devuelve la misma respuesta sin volver a notificar al proveedor. Si la factura ya estaba pagada, la respuesta es 200 con ya_estaba_pagada: true (idempotente); si todavía está en trámite, sin conformidad, responde 422 estado_invalido y no se paga.
Puedes consultar el pago después con GET /purchase_requisitions_status.php: cada factura del bloque entregas_factura trae ahora su estado_pago y, si aplica, su pagado_at.
Tu propio código de material
Tu código interno (SAP, UNSPSC u otro propio) no tiene por qué coincidir con el código de categoría de PIZ — la homologación es la tabla de equivalencia entre ambos.
En Mi organización → Integraciones API, sección "Homologación de catálogo": escribes tu código tal cual lo usa tu ERP, y eliges a mano la categoría de PIZ a la que corresponde — el selector muestra el nombre y el código interno de PIZ de cada categoría (ej. Aditivos para concreto — CON-023) para que puedas ubicar la correcta. No hay match automático por texto; es una asociación manual, una vez por código, que después se reutiliza sola en cada SOLPED nueva.
categoria_codigo es obligatorio. PIZ primero busca en tu tabla de homologación; si no está ahí, intenta hacer match directo contra su catálogo global (por si tu código ya coincide con el de PIZ).
categoria_codigo no coincide con ninguna homologación tuya ni con el catálogo global, la API responde 400 categoria_no_encontrada y no se crea nada. Homologa el código primero (sección anterior) y vuelve a intentar.
Errores
| Código | Significado | Qué hacer |
|---|---|---|
400 campo_invalido | Falta un campo obligatorio o el tipo no calza (incluye items faltante o vacío en bienes) | El mensaje nombra el campo exacto |
400 categoria_no_encontrada | categoria_codigo no coincide con tu homologación ni con el catálogo global | Homológalo primero en Mi organización → Integraciones API |
401 token_invalido | Token vencido o mal formado | Pide uno nuevo |
403 scope_insuficiente | Tu credencial no tiene el scope de este endpoint | Pide que te lo agreguen |
404 no_encontrado | No hay ninguna factura (o RFQ) con esa referencia para tu organización | Revisa el factura_codigo / oc_codigo — solo ves las de tu organización |
409 idempotency_conflict | Reusaste un Idempotency-Key con un body distinto | Genera una key nueva por cada operación real |
422 estado_invalido | La factura todavía no está aprobada (sin conformidad), no se puede pagar | Reintenta cuando el comprador le dé conformidad |
429 rate_limit | Superaste el límite de la sección siguiente | Reintenta respetando Retry-After |
Sandbox, versiones, límites
| Aspecto | Regla |
|---|---|
| Sandbox | Ambiente separado, datos de prueba propios — pídelo junto con tus credenciales |
| Versionado | Prefijo /api/v1/ — un cambio incompatible sale como v2 nuevo, v1 sigue viva con aviso previo |
| Rate limit | 60 solicitudes/minuto por credencial y por endpoint (SOLPED, aviso de pago, etc.) |
Seguridad
- TLS 1.2+ obligatorio en ambos sentidos.
- El
client_secretse muestra una sola vez — si se pierde, se rota. - Las URL de factura/guía expiran a las 72 horas.