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.
Ambos son asíncronos. Enviar una SOLPED confirma solo que PIZ la recibió — la RFQ queda en borrador hasta que un comprador la revisa y publica.
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 |
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). |
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"
}
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.
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 |
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) y presupuesto_referencial (decimal, opcional, por ítem). 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": [
{ "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.
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.
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.
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.
Podés 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 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.
| 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 |
| 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.) |
client_secret se muestra una sola vez — si se pierde, se rota.