Pedidos en JSON: esquema ph.order/1.2
Payload versionado de pedidos ph.order/1.2: esquema JSON publicado, reglas de compatibilidad y ejemplos de entrega.
Cuando se confirma una venta, el pedido se entrega en la integración (webhook, SFTP o correo) con este JSON canónico y versionado. Esta página es la especificación exacta del formato ph.order/1.2.
Reglas de formato
- Todas las claves están siempre presentes; las claves nunca se omiten.
- null significa «dato desconocido»; no debe interpretarse como 0 (algunos canales no desglosan impuestos por línea).
- Los importes son números con hasta 2 decimales.
- tax_rate es un decimal: 0.21 equivale al 21 %.
- channel es el código interno del canal (p. ej. ebay, wllp) y channel_name su nombre visible (p. ej. Ebay, Wallapop).
- total_gross es el precio de venta para el vendedor, con la comisión del vendedor incluida: channel_fees_gross (lo que el canal le retiene de ese importe) y buyer_fees_gross (lo que el comprador paga al canal además del precio, nunca dentro de total_gross) son informativos; shipping_gross (transporte) también lo es, y puede estar incluido o no en total_gross según el canal (las lines dan el desglose de la mercancía).
Ejemplo de payload
{
"schema": "ph.order/1.2",
"order_id": "123456789",
"channel": "ebay",
"channel_name": "Ebay",
"created_at": "2026-06-18T10:32:00+00:00",
"status": "accepted",
"currency": "EUR",
"original_currency": "EUR",
"exchange_rate": 1.0,
"customer": {
"foreign_id": "a1b2c3d4",
"first_name": "Toni",
"last_name": "Bosch",
"company_name": null,
"email": "toni.bosch@example.com",
"tax_number": "12345678Z",
"phone": "+34600000000",
"address": {
"street": "Carrer Major 1",
"city": "Campdevànol",
"province": "Girona",
"postal_code": "17530",
"country": "ES"
}
},
"lines": [
{
"external_id": "ITEM-001",
"title": "Faro delantero izquierdo",
"quantity": 1,
"line_net": 100.00,
"line_tax": 21.00,
"line_gross": 121.00,
"tax_rate": 0.21
}
],
"shipping_gross": 10.00,
"channel_fees_gross": 13.00,
"buyer_fees_gross": null,
"total_net": 100.00,
"total_tax": 21.00,
"total_gross": 131.00,
"carrier": "Correos",
"tracking_code": "AB123456789ES",
"tracking_url": "https://tracking.example.com/AB123456789ES",
"payment_method": "card",
"source_account": null
}
Campos
| Campo | Tipo | Descripción |
|---|---|---|
schema | string | Identificador del esquema y su versión, «ph.order/MAYOR.MENOR» (hoy ph.order/1.2). Fijarse solo en el mayor. |
order_id | string | Identificador único del pedido. |
channel | string | Código interno del canal de venta (p. ej. ebay, wllp). |
channel_name | string | Nombre visible del canal de venta (p. ej. Ebay, Wallapop). |
created_at | string | null | Fecha y hora de creación del pedido, en formato ISO 8601. |
status | string | Estado del pedido (p. ej. accepted). Lista de valores abierta. |
currency | string | null | Moneda de los importes del pedido en formato ISO 4217 (p. ej. EUR). |
original_currency | string | null | Moneda en la que pagó el comprador, en formato ISO 4217. Si es otra, el pedido se convirtió y sus importes están en currency. |
exchange_rate | number | null | Unidades de original_currency que valía una unidad de currency al convertir el pedido (p. ej. 0.8346 libras por euro); 1 si no se convirtió. |
customer | object | Datos del comprador (objeto; ver campos más abajo). |
lines | array | Líneas del pedido, una por artículo (lista de objetos; ver campos más abajo). |
shipping_gross | number | null | Importe del envío con impuestos incluidos. |
channel_fees_gross | number | null | Comisión que el canal retiene al vendedor por el pedido (informativo; incluida en total_gross, el canal la descuenta del cobro). |
buyer_fees_gross | number | null | Cargos que el comprador paga al canal además del precio, p. ej. la protección de compra (informativo; no forma parte de total_gross). |
total_net | number | null | Base imponible total del pedido (sin impuestos). |
total_tax | number | null | Importe total de impuestos del pedido. |
total_gross | number | null | Precio de venta para el vendedor, impuestos y comisión del vendedor incluidos (el envío puede estar incluido o no según el canal). |
carrier | string | null | Transportista del envío. |
tracking_code | string | null | Código de seguimiento del envío. |
tracking_url | string | null | URL de seguimiento del envío. |
payment_method | string | null | Método de pago (p. ej. card). Lista de valores abierta. |
source_account | string | null | Cuenta de origen en el canal de venta, si aplica. |
customer.foreign_id | string | null | Identificador del comprador en el canal de origen. |
customer.first_name | string | null | Nombre del comprador. |
customer.last_name | string | null | Apellidos del comprador. |
customer.company_name | string | null | Razón social del comprador, si es una empresa. |
customer.email | string | null | Correo electrónico del comprador. |
customer.tax_number | string | null | Identificación fiscal del comprador (NIF/CIF/VAT). |
customer.phone | string | null | Teléfono del comprador. |
customer.address | object | Dirección de envío del comprador (objeto; ver campos más abajo). |
customer.address.street | string | null | Calle y número de la dirección de envío. |
customer.address.city | string | null | Población de la dirección de envío. |
customer.address.province | string | null | Provincia o región de la dirección de envío. |
customer.address.postal_code | string | null | Código postal de la dirección de envío. |
customer.address.country | string | null | País de la dirección de envío, en formato ISO 3166-1 alpha-2 (p. ej. ES). |
lines[].external_id | string | null | Identificador del artículo en el catálogo (SKU o referencia). |
lines[].title | string | null | Título o descripción del artículo. |
lines[].quantity | integer | null | Unidades del artículo en esta línea. |
lines[].line_net | number | null | Base imponible de la línea (sin impuestos). |
lines[].line_tax | number | null | Importe de impuestos de la línea. |
lines[].line_gross | number | null | Importe de la línea con impuestos incluidos. |
lines[].tax_rate | number | null | Tipo impositivo de la línea en decimal (0.21 = 21 %). |
Compatibilidad y versiones
Para no tener que volver a tocar la integración en futuras versiones, conviene construir el lector siguiendo estas reglas:
- Versionado: el campo schema es ph.order/MAYOR.MENOR (hoy ph.order/1.2). Fijarse solo en el MAYOR (el 1) y aceptar cualquier versión menor.
- Versiones publicadas: 1.0, el esquema inicial. 1.1 añade buyer_fees_gross y deja channel_fees_gross como la comisión que el canal cobra al vendedor en todos los canales; en Wallapop contenía la protección de compra del comprador, que pasa a buyer_fees_gross. 1.2 añade original_currency y exchange_rate: un pedido pagado en otra moneda llega con los importes en euros, y estos campos dicen en qué moneda pagó el comprador y a qué cambio.
- Solo se añade, nunca se quita: dentro de la versión mayor 1 los cambios son aditivos. Se podrán añadir campos nuevos (siempre presentes, con null cuando no apliquen), pero nunca se eliminará, renombrará ni se cambiará el tipo o el significado de un campo existente. Única excepción: la de 1.1 indicada en las versiones publicadas.
- Ignorar los campos no reconocidos: el lector debe descartarlos sin fallar (no validar con additionalProperties: false).
- Listas de valores abiertas: en status, channel, payment_method, currency y original_currency pueden aparecer valores nuevos; tratar un valor desconocido sin romper (p. ej. como «otro»).
- Solo un cambio de versión MAYOR (ph.order/2.0) requeriría adaptación, y se avisaría con antelación; las versiones menores no exigen ningún cambio por parte del consumidor, salvo la excepción de 1.1 indicada arriba.
Para validar con un JSON Schema, se facilita uno laxo para ph.order/1.x que ya contempla todo esto (acepta campos nuevos y cualquier versión menor). Para coordinar el cambio o solicitar el esquema y payloads de prueba, contactar con el responsable en Portal Hero.