Documentación Shipping
Tarifas, creación y gestión de envíos: endpoints, parámetros y ejemplos listos para usar.
Partner Developer Program Integración E-commerce (módulos / conectores)
Guía rápida para desarrollar tu propio módulo/conector y conectar tu e-commerce con Shipping Z-Bombilla: registrar tienda, abrir la pasarela de envío y recibir el tracking por callback.
Flujo recomendado
Se obtiene desde
shipping.z-bombilla.com/ecommerces y se pega en el módulo del e-commerce.
Ese mismo token se usa para autenticar el callback de tracking.
platform debe ser un identificador en minúsculas (ej: prestashop, woocommerce o uno propio).instanceId debe ser estable por tienda (ej: dominio + id shop). Si cambias el instanceId, será “otra tienda”.
Paso a paso
-
Solicitar AccessToken al usuario (desde
/ecommerces) y guardarlo en la configuración del módulo. -
Registrar tienda (conexión) usando el endpoint de conexión:
ver “Registrar tienda”.
Aquí se guarda:
platform,siteUrl,apiBase,instanceIdy, muy importante,trackingCallbackUrl(URL pública del e-commerce que recibirá el tracking). -
En el panel de pedidos (admin), añade un botón “Enviar a Shipping” que abra una pestaña nueva y haga:
POST /nuevoEnvio con
envioJson(Base64 JSON) y opcionales comoitemsJsonyalertasMarketplace. - Shipping devuelve el tracking por callback a tu módulo (e-commerce) vía: Callback tracking (webhook).
-
Mostrar tracking en:
- panel admin (listado de pedidos + ficha del pedido)
- cuenta cliente / detalle del pedido
- email (si el e-commerce lo soporta)
UI recomendada en el módulo
Backoffice (panel de pedidos)
-
Botón “Enviar a Shipping” en la ficha del pedido (abre pestaña nueva).
El botón hace un
POSThacia/nuevoEnvio(autopost). - Columna en el listado (opcional): icono camión + tracking (si existe). Si hay tracking, al hacer clic muestra un modal de seguimiento (ver más abajo).
-
Alertas del pedido: si bloqueas o adviertes, pasa mensajes en
alertasMarketplacepara que Shipping las pinte en pantalla (ej: “ya enviado”, “estado no permitido”, etc.).
envioJson + extras, renderiza un HTML con un <form>
y hace autosubmit a Shipping.
Frontoffice (cuenta cliente)
- Tarjeta “Seguimiento del envío” con tracking + transportista.
- Botón “Ver seguimiento” que abre un modal con el seguimiento embebido (iframe) o una pestaña nueva.
Modal de seguimiento (admin + cliente)
Implementación recomendada hoy: embebe la URL web de seguimiento de Shipping:
https://shipping.z-bombilla.com/envio/seguimiento?numSeguimiento=TRACKING.
Estados en JSON: si tu plataforma ya tiene un endpoint propio de estados, puedes llamarlo desde el modal. Si no, usa el iframe. (Más adelante podrás sustituir el iframe por un
fetch a un endpoint de estados cuando se publique).
Snippet (HTML + JS vanilla, sin dependencias)
<!-- Botón / link (admin o cliente) -->
<a href="#" class="zb-open-tracking" data-trk="PQ29BT071019809B">
Ver seguimiento
</a>
<!-- Modal simple -->
<div id="zbTrackModal" style="display:none; position:fixed; inset:0; z-index:99999;">
<div id="zbTrackBackdrop" style="position:absolute; inset:0; background:rgba(0,0,0,.55);"></div>
<div style="position:relative; max-width:980px; margin:5vh auto; background:#fff; border-radius:10px; padding:12px; box-shadow:0 10px 35px rgba(0,0,0,.35);">
<button type="button" id="zbTrackClose"
style="position:absolute; top:8px; right:10px; background:transparent; border:0; font-size:28px; line-height:28px; cursor:pointer;">
×
</button>
<div style="padding:6px 6px 10px 6px; border-bottom:1px solid #eee;">
<strong>Seguimiento del envío</strong>
<a id="zbTrackOpenNew" href="#" target="_blank" rel="noopener" style="float:right; font-size:13px;">Abrir en pestaña nueva</a>
</div>
<div style="padding:10px 6px 0 6px;">
<iframe id="zbTrackFrame" src="about:blank" style="width:100%; height:70vh; border:0;" loading="lazy"></iframe>
<div style="margin-top:10px;">
<div style="padding:10px; border:1px solid #ffeeba; background:#fff3cd; border-radius:6px; font-size:13px;">
Si no se muestra el contenido, usa “Abrir en pestaña nueva”.
</div>
</div>
</div>
</div>
</div>
<script>
(function(){
function q(sel, root){ return (root||document).querySelector(sel); }
function qa(sel, root){ return Array.prototype.slice.call((root||document).querySelectorAll(sel)); }
var modal = q('#zbTrackModal');
var frame = q('#zbTrackFrame');
var openNew = q('#zbTrackOpenNew');
var closeBtn = q('#zbTrackClose');
var backdrop = q('#zbTrackBackdrop');
function buildUrl(trk){
trk = (trk||'').trim();
return trk ? ('https://shipping.z-bombilla.com/envio/seguimiento?numSeguimiento=' + encodeURIComponent(trk)) : '';
}
function openModal(trk){
var url = buildUrl(trk);
if(!url) return;
frame.src = url;
openNew.href = url;
modal.style.display = 'block';
}
function closeModal(){
modal.style.display = 'none';
frame.src = 'about:blank';
}
qa('.zb-open-tracking').forEach(function(a){
a.addEventListener('click', function(ev){
ev.preventDefault();
openModal(a.getAttribute('data-trk') || '');
});
});
closeBtn.addEventListener('click', closeModal);
backdrop.addEventListener('click', closeModal);
document.addEventListener('keydown', function(e){
if(e && e.keyCode === 27 && modal.style.display === 'block') closeModal();
});
})();
</script>
Callback de tracking (resumen técnico)
| Elemento | Detalle |
|---|---|
| Método | POST JSON |
| Auth | Authorization: Bearer <accessToken> (comparación constante) |
| Body |
{ order_id, tracking, carrier, shipped_at }
|
| Respuesta | 200 con { "ok": true } |
Implementaciones avanzadas (masivo / empresas)
1) Cotizar + generar etiqueta (calcular-envio ➜ do-envio)
- Llamas a calcular-envio para obtener precio/servicio de todas las agencias disponibles según bultos y destino.
- El usuario (o tu lógica) elige una agencia/servicio.
- Llamas a do-envio indicando la agencia elegida y recibes etiqueta + tracking.
- Si la tienda está conectada, Shipping notificará el tracking al e-commerce por callback (si está configurado).
2) Generación automática (do-envio con reglas ya configuradas)
Para operativas avanzadas, puedes preconfigurar reglas en Shipping (preferencias por calidad/precio/rapidez, horarios, recogidas, etc.) y lanzar do-envio para que Shipping elija el mejor servicio automáticamente.
Este flujo reduce lógica en el e-commerce y centraliza decisiones en Shipping.
/nuevoEnvio Pasarela de creación de envío
Abre Shipping con datos precargados (envío + destinatario + bultos) y, opcionalmente, productos y alertas del pedido.
Resumen
envioJson y muestra el formulario con los datos precargados.
Autenticación
accessToken para auto-login/autorización (según tu flujo).
Parámetros
| Nombre | Tipo | Oblig. | Descripción |
|---|---|---|---|
envioJson |
string (Base64 JSON) | Sí | Base64 del JSON de EnvioV3DTO (UTF-8). Es el payload principal. |
idExpedicion |
number | No | Si se envía, Shipping carga una expedición existente y precarga el formulario (editar/duplicar). |
marketplaceName |
string | No | Nombre del marketplace para rotular el bloque de productos (ej. WooCommerce, PrestaShop). |
itemsJson |
string (Base64 JSON) | No | Lista de productos/líneas del pedido. Ver detalle |
alertasMarketplace |
string (JSON/Base64) | No | Lista de alertas del pedido. Ver detalle |
order_id |
string/number | No | ID de pedido del marketplace (para asociar tracking u operaciones posteriores). |
combined |
0/1 | No | Si 1, Shipping pinta productos por pedido (modo combinado). |
accessToken |
string | No | Token para auto-login/autorización (si tu integración lo soporta). |
salesChannelUrl |
string (URL) | No | Enlace directo al pedido en el marketplace/panel (por ejemplo, la edición del pedido en el backoffice). Shipping puede mostrarlo como acceso rápido tipo “Ver pedido”. Compatibilidad: también se acepta dentro de 'envioJson'. |
envioJson. Si envías idExpedicion, puede no ser necesario envioJson (dependiendo del flujo).
Cómo construir envioJson
JSON de EnvioV3DTO codificado en Base64 (UTF-8).
const codificado = btoa(unescape(encodeURIComponent(JSON.stringify(envio))));
Ejemplo de JSON (antes de Base64)
{
"refEnvio":"WC-12345",
"tipoPortes":"Pagados",
"valorTotal":59.90,
"destinatario":{
"nombre":"Cliente SL",
"direccion":"Calle Falsa 123, 1",
"codigoPostal":"28001",
"poblacion":"Madrid",
"provincia":"Madrid",
"pais":{"isoCode":"ES"},
"telefono":"600000000",
"email":"cliente@email.com",
"observaciones":""
},
"olBultos":[{"largo":30,"ancho":20,"alto":10,"peso":1.2}],
"salesChannelUrl":"https://tu-tienda.com/panel/index.php?controller=AdminOrders&id_order=12345&vieworder"
}
itemsJson · productos del pedido
Si envías itemsJson, Shipping podrá pintar el bloque Productos Marketplace (tabla).
El frontend es flexible: usa name/title, image/img, sku/sellerSKU,
qty/quantity y price/itemPriceAmount.
form-urlencoded.
Campos detectados por el frontend
| Uso | Campos aceptados |
|---|---|
| Título | name o title |
| Imagen | image o img |
| SKU | sku / sku_id / sellerSKU |
| Cantidad | qty / quantity / quantityOrdered |
| Precio | price o itemPriceAmount |
| Link producto | idProduct + linkProduct (si existen) |
| Fila gastos envío | isShippingFee = true + name + price |
Ejemplo JSON (antes de Base64)
[
{"name":"Producto 1","sku":"REF1","qty":2,"price":8.264,"image":"https://tuweb/img1.jpg"},
{"isShippingFee":true,"name":"Gastos de envío","price":4.95}
]
alertasMarketplace · alertas del pedido
Si envías alertasMarketplace, Shipping lo convierte a List<String> y lo pinta como lista en “Alertas del pedido”.
Ejemplo JSON (antes de Base64)
[
"Este pedido ya consta como ENVIADO (TRK: 1234567890).",
"El pedido no está listo porque su estado actual es En espera.",
"Pedido marcado como urgente"
]
/oauth/ecommerce/callback Registrar tienda / conectar marketplace
Registra (o actualiza) una tienda/instancia de marketplace en Shipping para poder: recibir callbacks de tracking y asociar pedidos/seguimientos a esa instancia. Normalmente se abre desde el BackOffice del marketplace (botón “Conectar”).
Resumen
token es un secreto (shared secret).
En callbacks, el marketplace debe validar Authorization: Bearer <token>.
Usa siempre HTTPS y evita registrar el token en logs.
Autenticación
token (AccessToken).
Shipping lo almacena asociado a la instancia para autenticar callbacks posteriores.
Parámetros (QueryString)
| Nombre | Tipo | Oblig. | Descripción |
|---|---|---|---|
platform |
string | Sí | Plataforma / conector. Ej: prestashop, woocommerce. |
siteUrl |
string (URL) | Sí | URL base de la tienda. Ej: https://www.tienda.com (con o sin idioma). |
apiBase |
string (URL) | No | Base para llamadas API del marketplace (si aplica). Normalmente igual que siteUrl. |
shopId |
string/number | No | ID de tienda (útil en multishop). Ej: 1. |
psVersion |
string | No | Versión de PrestaShop (si aplica). Ej: 1.6.0.8. |
moduleVersion |
string | No | Versión del módulo/conector. Ej: 0.2.0. |
trackingCallbackUrl |
string (URL) | Sí |
URL del marketplace a la que Shipping enviará el tracking vía POST JSON. Ej (PrestaShop): https://www.tienda.com/module/shippingzb/trackingupdate
|
token |
string | Sí |
Secreto compartido (AccessToken). Se usará como Bearer en callbacks:Authorization: Bearer <token>
|
trackingCallbackUrl debe aceptar:
- Método: POST
- Headers:
Authorization: Bearer <token>,Content-Type: application/json - Body:
{"order_id":..., "tracking":"...", "carrier":"...", "shipped_at":"..."}
Ver contrato del webhook:
Callback de tracking (POST JSON)
/envio/calcularEnvio Tarificación
Calcula las tarifas disponibles para un envío según destino, código postal, valor de mercancía y bultos.
Resumen
isGood indica si la tarifa es válida).
Autenticación
Incluye el token en cabecera:
Authorization: Bearer {accessToken}
Cabeceras
| Cabecera | Valor | Obligatorio |
|---|---|---|
Authorization |
Bearer {accessToken} |
Sí |
Content-Type |
application/x-www-form-urlencoded |
Sí |
Parámetros
| Parámetro | Tipo | Oblig. | Descripción |
|---|---|---|---|
codigoPostal |
string | Sí | Código postal de destino. |
paisCliente |
string | No | Código ISO (ej. ES) o ID del país. Por defecto: ES. |
tipoPortes |
string | No | Pagados (por defecto) o Contrareembolso. |
valorMercancia |
decimal | Cond. | Opcional si el país es ES. Obligatorio y > 0 para otros países. |
largo[], ancho[], alto[], peso[] |
array (repetible) | Sí |
Los bultos se envían como arrays usando la notación con corchetes
en application/x-www-form-urlencoded (o como parámetros de query).Importante: todas las listas deben tener el mismo número de valores (mismo nº de bultos). Ejemplo (1 bulto): largo[]=20&ancho[]=30&alto[]=40&peso[]=5Ejemplo (2 bultos): largo[]=20&ancho[]=30&alto[]=40&peso[]=5&largo[]=10&ancho[]=10&alto[]=10&peso[]=21Nota: si tu cliente/URL encoder lo requiere, los corchetes pueden ir escapados como largo%5B%5D.
Ejemplo estilo Postman (querystring):
POST /envio/calcularEnvio?tipoPortes=Pagados&valorMercancia=10&paisCliente=ES&codigoPostal=03501&largo[]=20&ancho[]=30&alto[]=40&peso[]=5&largo[]=10&ancho[]=10&alto[]=10&peso[]=21
|
Respuesta (HTTP 200)
Lista de agencias con tarifas calculadas:
[
{
"nombreAgenciaCalculada": "CorreosExpress",
"precioPorte": 4.52,
"precioSeguro": 100.00,
"precioReembolso": 0.00,
"precioTotal": 4.52,
"isGood": true,
"errors": []
}
]
- precioSeguro: no es un coste, es el importe máximo cubierto en caso de incidencia.
- isGood: valida que la agencia puede calcular la tarifa correctamente.
Errores (HTTP 400)
Si faltan campos o hay validaciones, se devuelve un JSON con errores:
{
"errores": [
"codigoPostal es obligatorio",
"valorMercancia debe ser mayor que 0 para envíos fuera de España",
"Debe especificar al menos un bulto (largo, ancho, alto, peso)"
]
}
Notas
- Este endpoint solo calcula tarifas (no registra el envío).
- Valida
isGoodantes de usar la tarifa.
/codigoPostalLookup Lookup CP
Obtiene población y provincia a partir de un código postal.
Resumen
[]).
Autenticación
Parámetros (query)
| Parámetro | Tipo | Oblig. | Descripción |
|---|---|---|---|
codigoPostal |
string | Sí | Código postal del que obtener población y provincia. |
Ejemplo
GET https://shipping.z-bombilla.com/codigoPostalLookup?codigoPostal=03500
Respuesta (HTTP 200)
[
{
"poblacion": "Benidorm",
"codigoPostal": "03501",
"provincia": "Alicante"
}
]
Notas
- Devuelve siempre un array JSON.
- Si no hay coincidencias:
[].
/envio/doEnvioApi Confirmar envío (API)
Genera el envío definitivo, crea el tracking y devuelve las etiquetas en Base64.
Resumen
/envio/doEnvioApi.El endpoint
/envio/doEnvio existe para uso web interno (sesión/JSESSIONID) y no sirve para integraciones por token.
Autenticación
Incluye el token en cabecera:
Authorization: Bearer {accessToken}
Cabeceras
| Cabecera | Valor | Obligatorio |
|---|---|---|
Authorization |
Bearer {accessToken} |
Sí |
Content-Type |
application/json |
Sí |
Parámetros del body (JSON)
| Campo | Tipo | Oblig. | Descripción |
|---|---|---|---|
agencia.nombreAgenciaCalculada |
string | Sí | Nombre de la agencia (obtenido desde Calcular Envío). Debe coincidir exactamente. |
agencia.precioPorte |
decimal | No |
Opcional (informativo). El sistema recalcula internamente y selecciona por nombreAgenciaCalculada.
|
envio.tipoPortes |
string | No (recomendado) | Pagados o Contrareembolso. Recomendado enviarlo siempre. |
envio.refEnvio |
string | No | Referencia interna (por ejemplo nº de pedido). |
envio.descripcionEnvio |
string | No |
Descripción del contenido. Recomendado para envíos internacionales / ciertas agencias.
Ej: "Papel Secamanos".
|
envio.destinatario.nombre |
string | Sí | Nombre del destinatario (máx. 120). |
envio.destinatario.direccion |
string | Sí | Dirección del destinatario (máx. 300). |
envio.destinatario.numero |
string | No | Número de dirección (máx. 45). |
envio.destinatario.paisISO |
string | No | ISO país. Por defecto ES. |
envio.destinatario.provincia |
string | No | Para España puede recalcularse desde el CP (máx. 45). |
envio.destinatario.poblacion |
string | No | Población del destinatario (máx. 45). |
envio.destinatario.codigoPostal |
string | Sí | Código postal (máx. 10). |
envio.destinatario.telefono |
string | No | Teléfono de contacto (máx. 20). |
envio.destinatario.email |
string | No | Email de contacto (máx. 120). |
envio.destinatario.observaciones |
string | No | Observaciones (máx. 300). |
envio.bultos |
array | Sí | Listado de bultos (mínimo 1, máximo 100). |
envio.bultos[].largo |
decimal | Sí | Largo (cm). |
envio.bultos[].ancho |
decimal | Sí | Ancho (cm). |
envio.bultos[].alto |
decimal | Sí | Alto (cm). |
envio.bultos[].peso |
decimal | Sí | Peso (kg). |
envio.valorMercancia |
decimal | Cond. |
Obligatorio y > 0 si paisISO != ES o si tipoPortes = Contrareembolso.
|
envio.envioConRetorno |
boolean | No | Indica retorno (solo algunas agencias). |
Respuesta (HTTP 200)
{
"numSeguimiento": "1234567890",
"olEtiquetas": [
"Base64Etiqueta1",
"Base64Etiqueta2"
]
}
- olEtiquetas: puede ser Base64 de PDF o imagen según agencia.
- numSeguimiento: tracking asignado al envío.
Errores
- 400 Bad Request: validación / faltan campos / agencia no disponible.
- 401 Unauthorized: token no enviado o inválido.
- 404 Not Found: URL incorrecta (por ejemplo usar
/api/...
{
"error": "Falta campo obligatorio: envio.destinatario.nombre"
}
Notas
- Se recomienda usar una agencia con
isGood = truedesde Calcular Envío. agencia.nombreAgenciaCalculadadebe coincidir exactamente con el valor devuelto en tarificación.- Para
Contrareembolso,valorMercanciadebe ser > 0.
/envio/seguimiento Seguimiento unificado
Endpoint de seguimiento: recibe un numSeguimiento, localiza la expedición y
muestra el estado según la agencia (Correos, MRW, UPS, etc.).
Ideal para abrir en modal/iframe en panel admin y para mostrar seguimiento en front.
Resumen
numSeguimiento (también soporta tracking de bulto).
Seguridad
datos=view está pensado como enlace público (para mostrar seguimiento).
Algunas acciones especiales como datos=pod pueden requerir sesión iniciada,
dependiendo de la agencia.
Parámetros
| Nombre | Tipo | Oblig. | Descripción |
|---|---|---|---|
numSeguimiento |
string | Sí | Número de seguimiento. Si corresponde a un bulto, el sistema intenta resolver la expedición igualmente. |
datos |
string | No |
Modo de salida. Por defecto: view.
|
Uso recomendado en Admin/Front (modal / iframe)
Para una integración rápida, abre el enlace en pestaña nueva. Para una UX pro, abre un modal con un <iframe>
apuntando a datos=view y añade fallback “Abrir en pestaña nueva”.
// URL (para modal, admin o front)
const trackingUrl =
"https://shipping.z-bombilla.com/envio/seguimiento?numSeguimiento=" +
encodeURIComponent(trackingNumber);
// Último estado (JSON compacto)
const lastStatusUrl =
"https://shipping.z-bombilla.com/envio/seguimiento?datos=ultimoestado&numSeguimiento=" +
encodeURIComponent(trackingNumber);
Códigos de respuesta
| HTTP | Cuándo ocurre |
|---|---|
400 |
Falta numSeguimiento o el formato no es válido para localizar expedición. |
404 |
No se localiza ninguna expedición/bulto con ese número de seguimiento. |
501 |
Agencia sin soporte de seguimiento (aún). |
401/403 |
Acceso denegado (p.ej. datos=pod sin sesión o sin permisos). |
500 |
Error interno de seguimiento. |
{trackingCallbackUrl} Callback de tracking (webhook)
Shipping llama al endpoint que registraste como trackingCallbackUrl para enviar el tracking al marketplace.
En PrestaShop sería el controller del módulo (ej: /module/shippingzb/trackingupdate).
Resumen
order_id del marketplace.
Autenticación
Authorization: Bearer <token>Ese
token es el que se registró al conectar la tienda (token en el endpoint de conexión).
accessToken dentro del JSON (solo si tu integración lo permite).
Headers
Content-Type: application/json; charset=UTF-8
Authorization: Bearer {token}
Body (JSON)
| Campo | Tipo | Oblig. | Descripción |
|---|---|---|---|
order_id |
number/string | Sí | ID del pedido en el marketplace (el que enviaste en /nuevoEnvio). |
tracking |
string | Sí | Número de seguimiento. |
carrier |
string | No | Nombre del transportista (texto). Ej: “Correos Paq. Estándar…”. |
shipped_at |
string (ISO-8601) | No | Fecha/hora del envío. Ej: 2026-02-21T22:10:00Z. |
accessToken |
string | No | Fallback opcional si no llega Authorization. Normalmente no es necesario. |
Ejemplo request
{
"order_id": 127308,
"tracking": "PQ29BT071019809B",
"carrier": "Correos Paq. Estándar (48-72h) (Zona 1)",
"shipped_at": "2026-02-21T22:10:00Z"
}
Respuesta
{"ok":true}
Errores típicos
| HTTP | Motivo |
|---|---|
405 | Método no permitido (solo POST). |
401 | Token inválido o ausente. |
400 | Body vacío o JSON inválido. |
422 | Falta order_id o tracking. |
404 | Pedido no encontrado en el marketplace. |
500 | Error interno guardando tracking/cambiando estado/enviando email. |
200 igualmente.