{
  "info": {
    "name": "OnBox API v1",
    "description": "Colección oficial de la API de OnBox Servicios Logísticos. Cargá la variable apiKey con tu clave.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.onboxservicioslogisticos.com"
    },
    {
      "key": "apiKey",
      "value": "obx_test_pegaTuClaveAca"
    }
  ],
  "item": [
    {
      "name": "Diagnóstico",
      "item": [
        {
          "name": "Verificar la clave",
          "request": {
            "method": "GET",
            "description": "Devuelve a qué cuenta pertenece tu clave, qué permisos tiene y cuánto te queda del límite. Es la primera llamada que conviene hacer.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/ping",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "ping"
              ]
            }
          }
        },
        {
          "name": "Ver tus últimas llamadas",
          "request": {
            "method": "GET",
            "description": "Las últimas llamadas hechas con tu clave, con su X-Request-Id, el código HTTP y cuánto tardaron. Sirve para depurar sin escribirnos.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/logs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "logs"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "",
                  "description": "1–200. Por defecto 50.",
                  "disabled": true
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Pedidos",
      "item": [
        {
          "name": "Listar pedidos",
          "request": {
            "method": "GET",
            "description": "Tus pedidos, paginados por cursor. Para sincronizar cada X minutos usá updatedSince en vez de barrer todo: te devuelve sólo lo que cambió.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/orders",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "orders"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "description": "Desde (YYYY-MM-DD), por fecha de pedido.",
                  "disabled": true
                },
                {
                  "key": "to",
                  "value": "",
                  "description": "Hasta (YYYY-MM-DD).",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "",
                  "description": "Filtrar por estado exacto, sin distinguir mayúsculas.",
                  "disabled": true
                },
                {
                  "key": "updatedSince",
                  "value": "",
                  "description": "Sólo lo modificado después de ese momento (ISO 8601). Ordena por updatedAt.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "1–200. Por defecto 50.",
                  "disabled": true
                },
                {
                  "key": "cursor",
                  "value": "",
                  "description": "Seguí desde acá. Viene en paging.nextCursor.",
                  "disabled": true
                }
              ]
            }
          }
        },
        {
          "name": "Detalle de un pedido",
          "request": {
            "method": "GET",
            "description": "El pedido completo con sus líneas de producto, dirección y estado. Acepta tanto el id nuestro como el externalId que nos mandaste.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/orders/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "orders",
                ":id"
              ]
            }
          }
        },
        {
          "name": "Crear un pedido",
          "request": {
            "method": "POST",
            "description": "Nos mandás el pedido y queda cargado con el stock reservado. Es idempotente: reenviar el mismo externalId (o la misma Idempotency-Key) devuelve el pedido que ya existe con duplicate: true, sin duplicar nada.",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"externalId\": \"SM-10045\",\n  \"buyer\": {\n    \"name\": \"Juan Perez\",\n    \"phone\": \"1155667788\"\n  },\n  \"shipping\": {\n    \"address\": \"Av. Mitre 750\",\n    \"city\": \"Avellaneda\",\n    \"zip\": \"1870\",\n    \"province\": \"Buenos Aires\"\n  },\n  \"items\": [\n    {\n      \"sku\": \"ABC-123\",\n      \"quantity\": 2,\n      \"unitPrice\": 15400\n    }\n  ],\n  \"amount\": 30800\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/orders",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "orders"
              ]
            }
          }
        },
        {
          "name": "Cancelar un pedido",
          "request": {
            "method": "POST",
            "description": "Anula un pedido que todavía no salió del depósito y libera lo reservado. Si ya se preparó o despachó devuelve 409: eso lo resolvemos con una persona, no por API. Cancelar algo ya cancelado devuelve 200.",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reason\": \"El comprador se arrepintió\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/orders/:id/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "orders",
                ":id",
                "cancel"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Stock",
      "item": [
        {
          "name": "Stock disponible",
          "request": {
            "method": "GET",
            "description": "Unidades disponibles por SKU. Es lo que se puede vender: ya tiene descontado lo reservado por pedidos abiertos.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/stock",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "stock"
              ],
              "query": [
                {
                  "key": "sku",
                  "value": "",
                  "description": "Un SKU puntual. Vacío devuelve todos.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "",
                  "description": "1–500. Por defecto 100.",
                  "disabled": true
                }
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Seguimiento",
      "item": [
        {
          "name": "Estado de un envío",
          "request": {
            "method": "GET",
            "description": "Estado vivo y línea de tiempo. Acepta el número de pedido o el de seguimiento del transportista.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/tracking/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "tracking",
                ":id"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "Listar tus webhooks",
          "request": {
            "method": "GET",
            "description": "Tus URLs registradas, con el conteo de fallas seguidas de cada una.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks"
              ]
            }
          }
        },
        {
          "name": "Registrar un webhook",
          "request": {
            "method": "POST",
            "description": "La URL tiene que ser https y de un dominio público. Te devolvemos el secret UNA sola vez: con ese secret validás la firma de cada aviso. El webhook queda escuchando desde ese momento; no reenviamos historia vieja.",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://tu-sistema.com/hooks/onbox\",\n  \"events\": [\n    \"order.status_changed\",\n    \"order.delivered\"\n  ],\n  \"description\": \"Producción\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks"
              ]
            }
          }
        },
        {
          "name": "Disparar una prueba",
          "request": {
            "method": "POST",
            "description": "Te mandamos un evento ping firmado igual que los reales y te devolvemos qué contestó tu servidor. Sirve para verificar la firma antes de salir a producción.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks/:id/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks",
                ":id",
                "test"
              ]
            }
          }
        },
        {
          "name": "Rotar el secret",
          "request": {
            "method": "POST",
            "description": "Genera un secret nuevo. El anterior sigue siendo válido 24 horas para que puedas desplegar sin ventana de corte: durante ese lapso aceptá cualquiera de los dos.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks/:id/rotate-secret",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks",
                ":id",
                "rotate-secret"
              ]
            }
          }
        },
        {
          "name": "Historial de entregas",
          "request": {
            "method": "GET",
            "description": "Los últimos 50 avisos que te mandamos, con el código que devolviste, los intentos y el error si lo hubo.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks/:id/deliveries",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks",
                ":id",
                "deliveries"
              ]
            }
          }
        },
        {
          "name": "Dar de baja",
          "request": {
            "method": "POST",
            "description": "Borra el webhook y su historial. También acepta DELETE sobre /v1/webhooks/{id}.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/webhooks/:id/delete",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhooks",
                ":id",
                "delete"
              ]
            }
          }
        }
      ]
    },
    {
      "name": "Entorno de prueba",
      "item": [
        {
          "name": "Mover un pedido de prueba",
          "request": {
            "method": "POST",
            "description": "Sólo con clave de prueba. Avanza un pedido simulado al estado que le pidas y dispara los webhooks de prueba como si fuera real. Es la forma de probar tu integración de punta a punta sin tocar producción.",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"status\": \"Despachado\",\n  \"tracking\": \"OCA-123456\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/v1/sandbox/orders/:id/advance",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "sandbox",
                "orders",
                ":id",
                "advance"
              ]
            }
          }
        },
        {
          "name": "Receptor de prueba",
          "request": {
            "method": "GET",
            "description": "Apuntá tu webhook a POST /dev/echo y después consultá acá para ver exactamente qué te mandamos: headers, firma y cuerpo, con la firma ya verificada de nuestro lado. Sirve para comparar contra tu implementación.",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/dev/echo",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "dev",
                "echo"
              ]
            }
          }
        }
      ]
    }
  ]
}