{
  "info": {
    "name": "DC Envíos · Integración nacional",
    "description": "Configura api_key solo en tu entorno local. Las solicitudes son de producción. Selecciona explícitamente token_cotizacion y confirma las operaciones que generan efectos. No hay sandbox público documentado.\n\nSobrepesos: consulta primero movimientos y luego saldo. El cobro se aplica al saldo cuando DC Envíos lo autoriza; estas solicitudes no cobran y no requieren un webhook. Conserva los ID de movimientos por cuenta y no vuelvas a descontar el cargo del saldo recibido. Solo se devuelven los 500 últimos movimientos; para pendientes consulta el reporte.\n\nInternacional: todavía no disponible con la llave API de esta colección. No reutilices un token de sesión del portal.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "apikey",
    "apikey": [
      {
        "key": "key",
        "value": "X-API-Key",
        "type": "string"
      },
      {
        "key": "value",
        "value": "{{api_key}}",
        "type": "string"
      },
      {
        "key": "in",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.dcenvios.lat",
      "type": "string"
    },
    {
      "key": "api_key",
      "value": "",
      "type": "string"
    },
    {
      "key": "token_cotizacion",
      "value": "",
      "type": "string"
    },
    {
      "key": "guia_id",
      "value": "",
      "type": "string"
    },
    {
      "key": "numero_guia",
      "value": "",
      "type": "string"
    },
    {
      "key": "cp",
      "value": "64000",
      "type": "string"
    },
    {
      "key": "busqueda_sat",
      "value": "pantalones",
      "type": "string"
    },
    {
      "key": "confirmar_compra",
      "value": "false",
      "type": "string"
    },
    {
      "key": "confirmar_cancelacion",
      "value": "false",
      "type": "string"
    },
    {
      "key": "confirmar_recoleccion",
      "value": "false",
      "type": "string"
    },
    {
      "key": "fecha_recoleccion",
      "value": "YYYY-MM-DD",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Consultar saldo",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/balance",
        "description": "Saldo disponible de la cuenta vinculada a tu llave, en MXN. Si aún no existe un saldo, puede devolver 0 como número. Es el saldo que ya considera los cargos aplicados por administración. No vuelvas a descontar los movimientos de cargo_adicional. Esta lectura y /movimientos son solicitudes independientes, no una instantánea transaccional conjunta."
      },
      "response": []
    },
    {
      "name": "Consultar código postal",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/cp/{{cp}}",
        "description": "Obtén estado, municipio y colonias antes de cotizar. Conserva el nombre de la colonia seleccionada para generar la guía."
      },
      "response": []
    },
    {
      "name": "Buscar producto SAT",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/sat/buscar?q={{busqueda_sat}}",
        "description": "Busca por nombre o clave de 8 dígitos. Devuelve hasta 20 coincidencias. Una búsqueda de menos de 2 caracteres devuelve una lista vacía. Elige el producto correcto; no adivines la clave ni uses 01010101."
      },
      "response": []
    },
    {
      "name": "Cotizar un envío nacional",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/api/v1/quote",
        "description": "Devuelve las opciones disponibles para tu cuenta, ordenadas por precio ascendente. Elige una tarifa y conserva su token; vence a los 30 minutos. Repite la cotización si cambian CP, colonia, peso, dimensiones, seguro o embalaje.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"cp_origen\": \"64000\",\n  \"cp_destino\": \"06000\",\n  \"colonia_origen\": \"Centro\",\n  \"colonia_destino\": \"Centro\",\n  \"peso\": 1,\n  \"largo\": 20,\n  \"ancho\": 15,\n  \"alto\": 10,\n  \"satCategory\": \"53101500\",\n  \"tipo_embalaje\": \"box\",\n  \"asegurar\": false\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "response": []
    },
    {
      "name": "Generar una guía",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/api/v1/label",
        "description": "Esta operación compra una guía y descuenta el saldo. Usa el token elegido, direcciones completas y una clave SAT vigente. Seguro, valor declarado y embalaje se toman de la cotización. Conserva id, numero_guia, estatus y cualquier advertencia. Una misma cotización tiene control de duplicados; consulta la sección de reintentos.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"token_cotizacion\": \"{{token_cotizacion}}\",\n  \"remitente\": {\n    \"nombre\": \"Tienda Ejemplo\",\n    \"empresa\": \"Tienda Ejemplo\",\n    \"telefono\": \"8112345678\",\n    \"email\": \"remitente@example.com\",\n    \"cp\": \"64000\",\n    \"estado\": \"Nuevo León\",\n    \"ciudad\": \"Monterrey\",\n    \"colonia\": \"Centro\",\n    \"calle\": \"Morelos\",\n    \"numero\": \"100\",\n    \"referencias\": \"Local a pie de calle\"\n  },\n  \"destinatario\": {\n    \"nombre\": \"Cliente Ejemplo\",\n    \"telefono\": \"5512345678\",\n    \"email\": \"destinatario@example.com\",\n    \"cp\": \"06000\",\n    \"estado\": \"Ciudad de México\",\n    \"ciudad\": \"Cuauhtémoc\",\n    \"colonia\": \"Centro\",\n    \"calle\": \"Madero\",\n    \"numero\": \"5\"\n  },\n  \"paquete\": {\n    \"peso\": 1,\n    \"largo\": 20,\n    \"ancho\": 15,\n    \"alto\": 10,\n    \"contenido\": \"Pantalones de algodón\",\n    \"clave_sat\": \"53101500\"\n  }\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "response": [],
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (pm.variables.get('confirmar_compra') !== 'true') { pm.execution.skipRequest(); throw new Error('Revisa los datos y establece confirmar_compra=true para ejecutar esta operación de producción.'); }"
            ]
          }
        },
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const body = pm.response.json();",
              "if (body.id) pm.collectionVariables.set('guia_id', String(body.id));",
              "if (body.numero_guia) pm.collectionVariables.set('numero_guia', body.numero_guia);",
              "pm.collectionVariables.set('confirmar_compra', 'false');"
            ]
          }
        }
      ]
    },
    {
      "name": "Listar y buscar guías",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/labels?page=1&limit=20",
        "description": "Lista solo las guías de tu cuenta, de más reciente a más antigua. q busca por número, CP, estado, paquetería o nombre del remitente/destinatario. Una página superior a la última se ajusta a la última disponible. Para recuperar una operación pendiente, busca su id en la lista."
      },
      "response": []
    },
    {
      "name": "Obtener la etiqueta",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/label-pdf/{{guia_id}}",
        "description": "Devuelve JSON con base64, no un archivo PDF directo. El valor puede ser base64 puro o una data URL. Decodifícalo y detecta el formato: normalmente PDF, pero puede ser imagen. base64:null significa que la etiqueta aún no está disponible; consulta más tarde sin crear otra guía."
      },
      "response": []
    },
    {
      "name": "Rastrear una guía",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/tracking/{{numero_guia}}",
        "description": "Consulta el estado normalizado y sus eventos. Usa preferentemente las guías de tu cuenta. No hay una promesa de actualización en tiempo real ni de una frecuencia fija; recomendamos consultar cada 15–30 minutos, reducir la frecuencia después de la entrega y respetar el límite global."
      },
      "response": []
    },
    {
      "name": "Solicitar cancelación",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/api/v1/cancellations",
        "description": "Registra una solicitud; HTTP 201 no significa que la guía esté cancelada ni que el saldo haya sido devuelto. Se revisa antes de resolver. Si ya fue recolectada o registra movimiento físico, se rechaza. Consulta cancelacion_pendiente y estatus en /labels, y el saldo tras la resolución.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"numero_guia\": \"{{numero_guia}}\",\n  \"guide_id\": {{guia_id}},\n  \"motivo\": \"El pedido fue cancelado\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "response": [],
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (pm.variables.get('confirmar_cancelacion') !== 'true') { pm.execution.skipRequest(); throw new Error('Revisa los datos y establece confirmar_cancelacion=true para ejecutar esta operación de producción.'); }"
            ]
          }
        }
      ]
    },
    {
      "name": "Solicitar recolección",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{base_url}}/api/v1/recolecciones",
        "description": "Envía números de guías existentes y una dirección de origen común. fecha y horario se interpretan como hora local de recolección. La disponibilidad depende de la paquetería. automatica:false queda pendiente de gestión; automatica:true incluye la confirmación disponible. Puede ajustarse el horario. Evita repetir la solicitud si la respuesta se pierde: consulta primero el listado.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"fecha\": \"{{fecha_recoleccion}}\",\n  \"hora_ini\": \"09:00\",\n  \"hora_fin\": \"18:00\",\n  \"direccion\": {\n    \"nombre\": \"Tienda Ejemplo\",\n    \"empresa\": \"Tienda Ejemplo\",\n    \"telefono\": \"8112345678\",\n    \"email\": \"remitente@example.com\",\n    \"cp\": \"64000\",\n    \"estado\": \"Nuevo León\",\n    \"ciudad\": \"Monterrey\",\n    \"colonia\": \"Centro\",\n    \"calle\": \"Morelos\",\n    \"numero\": \"100\",\n    \"referencias\": \"Local a pie de calle\"\n  },\n  \"guias\": [\n    \"{{numero_guia}}\"\n  ],\n  \"num_paquetes\": 1,\n  \"comentarios\": \"Solicitar acceso en recepción\"\n}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        }
      },
      "response": [],
      "event": [
        {
          "listen": "prerequest",
          "script": {
            "type": "text/javascript",
            "exec": [
              "if (pm.variables.get('confirmar_recoleccion') !== 'true') { pm.execution.skipRequest(); throw new Error('Revisa los datos y establece confirmar_recoleccion=true para ejecutar esta operación de producción.'); }"
            ]
          }
        }
      ]
    },
    {
      "name": "Consultar recolecciones",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/recolecciones",
        "description": "Devuelve las 100 solicitudes más recientes de tu cuenta. Esta operación no implementa paginación. El indicador recolectado se calcula con los avances de rastreo de las guías; una solicitud registrada no equivale a un paquete recolectado."
      },
      "response": []
    },
    {
      "name": "Consultar movimientos y cargos",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/movimientos",
        "description": "Devuelve los 500 movimientos más recientes de tu cuenta, ordenados por fecha descendente. No implementa filtros ni paginación. Incluye cargos efectivamente aplicados y reembolsos. Identifica cada movimiento por id y utiliza saldo_anterior/saldo_nuevo para determinar su efecto; no interpretes el signo de monto de forma aislada. Un ajuste aún pendiente puede no aparecer aquí. Los cargos se descuentan del saldo disponible cuando administración los autoriza; no se cobra mediante esta consulta ni se emite un webhook al cliente. Si no alcanza el saldo, puede quedar una parte pendiente. No supongas que una recarga cobra automáticamente lo pendiente. Guarda cada id con unicidad por cuenta; no restes de nuevo el cargo al saldo devuelto por /balance. Con más de 500 movimientos entre consultas, esta ruta no garantiza recuperar todos los registros."
      },
      "response": []
    },
    {
      "name": "Descargar reporte de guías y ajustes",
      "request": {
        "method": "GET",
        "header": [],
        "url": "{{base_url}}/api/v1/labels/reporte.csv",
        "description": "Exporta las guías de tu cuenta en CSV UTF-8 con BOM, encabezados, comas y campos entre comillas. No implementa filtros ni paginación. Incluye Total original, Ajustes posteriores, Conceptos de ajustes, Ajustes cobrados, Ajustes pendientes y Total final. Los ajustes corresponden a los registrados en la plataforma; Total final suma el original y los ajustes reportados, aunque una parte siga pendiente. Las fechas se muestran en America/Mexico_City."
      },
      "response": []
    }
  ]
}
