{
  "info": {
    "name": "NexoID · API v1",
    "description": "Resolución de RUC y DNI peruanos con procedencia auditable.\n\n## Antes de empezar\n\n1. **Ya funciona tal cual**: la variable `token` trae el **token público del sandbox**, que responde con un conjunto fijo y sintético de documentos (la lista, en `/docs/sandbox`). Pulsa **Send** en «RUC del sandbox».\n2. Para datos reales, pon **tu** token `nxid_live_…` en `token` (pestaña Variables) y usa las peticiones de RUC real.\n3. `base_url` ya apunta a producción. La autenticación (Bearer) está puesta a nivel de colección.\n\n## 🚩 El token completo NO es el que ves en tu lista de tokens\n\nEl error más común (un **401 token_invalido**) es usar el **prefijo** en vez del **secreto completo**.\n\n- La lista de tokens enseña solo `nxid_live_ab12cd34` — son **18 caracteres**, un identificador, NO el secreto.\n- El token completo son **42 caracteres**: `nxid_live_` (o `nxid_test_`) + 32 aleatorios. Se ve **una sola vez**, al emitirlo.\n- Si lo perdiste, pídenos uno nuevo por WhatsApp y revocamos el anterior. Solo guardamos su hash: recuperarlo es imposible por diseño.\n- Un token **de prueba** (`nxid_test_`) responde con el **sandbox**, nunca con el padrón real: no consume cuota y no se cobra. Con la cabecera `X-Nexoid-Simular: 429` o `503` provocas ese error. Para datos reales, uno `nxid_live_`.\n\n## Tres cosas que sorprenden a todo el mundo\n\n- 🔒 **Un RUC que empieza en `10`, `15` o `17` es una PERSONA NATURAL.** Su nombre es un dato de identidad, así que `GET /ruc/10724923530` exige el scope `dni.read` y que tu cuenta tenga finalidad y base legal declaradas — igual que `GET /dni/72492353`. Un token con solo `ruc.read` recibe **403**. Para una empresa (RUC que empieza en `20`) no hace falta nada de eso.\n- 🔒 **Un 404 no siempre es «no existe».** Puede ser un documento que de verdad no está, o el servicio diciéndote de forma degradada «no puedo comprobarlo ahora». Se distinguen por `meta.degradado` y `meta.motivo`.\n- El bloque **`meta`** de cada respuesta lleva `origen`, `fecha_dato` y `request_id`: de dónde salió el dato, de cuándo es, y el id para cruzarlo con soporte. Guárdalo.\n\nEl contrato siempre al día está en `GET /openapi.json`.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://nexoid.victorllerena.com/id/v1",
      "type": "string"
    },
    {
      "key": "token",
      "value": "nxid_test_sandboxpublicodenexoidpruebas001",
      "type": "string",
      "description": "El token público del sandbox. Cámbialo por el tuyo (`nxid_live_…`) para consultar datos reales."
    },
    {
      "key": "ruc_sandbox",
      "value": "20999999906",
      "type": "string",
      "description": "Una empresa del sandbox: activa, habida y con la ficha completa."
    }
  ],
  "item": [
    {
      "name": "Salud y contrato",
      "item": [
        {
          "name": "Health — estado del servicio",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/health",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "health"
              ]
            },
            "description": "Público, sin token. Tienen que decir `ok`: `estado`, `dependencias.padron`, `dependencias.auditoria` y `dependencias.proxy`. Un 200 no basta: el padrón puede estar vacío con todo en verde."
          }
        },
        {
          "name": "OpenAPI — el contrato completo",
          "request": {
            "auth": {
              "type": "noauth"
            },
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/openapi.json",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "openapi.json"
              ]
            },
            "description": "El contrato OpenAPI 3.1, generado de las rutas reales. Puedes importar esta URL en Postman para regenerar la colección siempre al día."
          }
        }
      ]
    },
    {
      "name": "Demo de la landing (sin token)",
      "description": "La demo de la landing: solo RUC 20, sin token, con 10 consultas por minuto y 50 al día por IP. Responde con datos reales.",
      "item": [
        {
          "name": "Demo de RUC",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/demo/ruc/20131312955",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "demo",
                "ruc",
                "20131312955"
              ]
            },
            "auth": {
              "type": "noauth"
            }
          }
        },
        {
          "name": "Demo del tipo de cambio",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/demo/tipo-cambio?moneda=USD",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "demo",
                "tipo-cambio"
              ],
              "query": [
                {
                  "key": "moneda",
                  "value": "USD"
                }
              ]
            },
            "description": "El tipo de cambio del día sin token, para el conversor de la landing. 10 por minuto y 50 al día por IP.",
            "auth": {
              "type": "noauth"
            }
          }
        }
      ]
    },
    {
      "name": "Tu cuenta",
      "item": [
        {
          "name": "Me — tenant, plan y scopes efectivos",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/me",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "me"
              ]
            },
            "description": "Cuando algo dé 403, empieza aquí. `scopes_efectivos` es la INTERSECCIÓN de lo que permite tu plan con lo que lleva tu token — casi todos los 403 se explican viendo cuál de los dos falta."
          }
        },
        {
          "name": "Uso — consumo del periodo",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/uso",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "uso"
              ]
            },
            "description": "Consultas facturables del periodo en curso. Los 404 no cuentan."
          }
        }
      ]
    },
    {
      "name": "RUC",
      "item": [
        {
          "name": "RUC del sandbox",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/ruc/{{ruc_sandbox}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "{{ruc_sandbox}}"
              ]
            },
            "description": "Con el token público responde la empresa sintética, con `meta.origen: sandbox`. Con un token live, este RUC da 404: no existe."
          }
        },
        {
          "name": "RUC del sandbox · simular un 429",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "X-Nexoid-Simular",
                "value": "429"
              }
            ],
            "url": {
              "raw": "{{base_url}}/ruc/{{ruc_sandbox}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "{{ruc_sandbox}}"
              ]
            },
            "description": "Solo con un token de prueba: devuelve `rate_limit_excedido` con `Retry-After`, como el de verdad. Con `503`, una avería."
          }
        },
        {
          "name": "RUC de empresa real (tipo 20) — con tu token live",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/ruc/20131312955",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "20131312955"
              ]
            },
            "description": "Ficha de un contribuyente. Este ejemplo (20131312955 = SUNAT) es una EMPRESA, así que solo necesita el scope `ruc.read`. Devuelve nombre, estado, condición, ubigeo, actividad económica y más."
          }
        },
        {
          "name": "RUC de persona natural (tipo 10) 🔒 exige dni.read",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/ruc/10724923530",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "10724923530"
              ]
            },
            "description": "🔒 Un RUC que empieza en 10/15/17 es una persona natural: su nombre es identidad. Devuelve lo mismo que `GET /dni/72492353`, y por eso exige `dni.read` + finalidad y base legal declaradas + anexo firmado. Con solo `ruc.read` recibes **403 finalidad_no_declarada** o **403 scope_insuficiente**. Es la primera sorpresa de toda integración."
          }
        },
        {
          "name": "Buscar por razón social (solo empresas)",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/ruc/buscar?q=sandbox",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "buscar"
              ],
              "query": [
                {
                  "key": "q",
                  "value": "sandbox"
                }
              ]
            },
            "description": "Solo empresas (R4). Con el token público, `q=sandbox` devuelve las siete del sandbox; con uno live, busca en el padrón."
          }
        },
        {
          "name": "Batch de RUC (hasta 100)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "prueba-ruc-001",
                "description": "Clave única: repetir la misma devuelve el mismo resultado sin recobrar"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"documentos\": [\n    \"20999999906\",\n    \"20999999914\",\n    \"20131312955\"\n  ]\n}"
            },
            "url": {
              "raw": "{{base_url}}/ruc/batch",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ruc",
                "batch"
              ]
            },
            "description": "Hasta 100 RUC NOMBRADOS en un `Idempotency-Key`. Requiere `batch` + `ruc.read`. 🔒 El batch no dispara fallback externo: se resuelve solo contra el padrón. El token público no tiene `batch`: hace falta el tuyo."
          }
        },
        {
          "name": "Alta de proveedor",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/proveedor/{{ruc_sandbox}}",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "proveedor",
                "{{ruc_sandbox}}"
              ]
            },
            "description": "La ficha, si es agente de retención o buen contribuyente, sus inhabilitaciones vigentes del OSCE, si ya la vigilas y avisos. Una consulta. Solo RUC 20."
          }
        }
      ]
    },
    {
      "name": "DNI 🔒 (identidad)",
      "item": [
        {
          "name": "DNI 🔒 exige dni.read + finalidad declarada",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/dni/72492353",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "dni",
                "72492353"
              ]
            },
            "description": "🔒 Devuelve el nombre de la persona. Exige: el scope `dni.read` en el token Y en el plan, finalidad + base legal + anexo de tratamiento firmado en tu cuenta. Si falta algo → 403. Y si el DNI no está en el padrón y no tienes fallback externo configurado → 404 (parece «no existe», es «no puedo preguntarlo»). La respuesta lleva `Cache-Control: private, no-store`."
          }
        },
        {
          "name": "Batch de DNI (hasta 100) 🔒",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "prueba-dni-001"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"documentos\": [\"72492353\", \"99999999\"]\n}"
            },
            "url": {
              "raw": "{{base_url}}/dni/batch",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "dni",
                "batch"
              ]
            },
            "description": "Hasta 100 DNI nombrados. Requiere `batch` + `dni.read` + finalidad declarada."
          }
        }
      ]
    },
    {
      "name": "Tipo de cambio (BCRP)",
      "item": [
        {
          "name": "Tipo de cambio de hoy",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/tipo-cambio",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "tipo-cambio"
              ]
            },
            "description": "Compra y venta del día, del Banco Central de Reserva del Perú. Requiere `tc.read`, y es gratis: no consume cuota."
          }
        },
        {
          "name": "Tipo de cambio de una fecha",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/tipo-cambio/2026-09-01",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "tipo-cambio",
                "2026-09-01"
              ]
            },
            "description": "La fecha en formato YYYY-MM-DD."
          }
        },
        {
          "name": "Tipo de cambio por rango",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/tipo-cambio/rango?desde=2026-08-01&hasta=2026-08-31",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "tipo-cambio",
                "rango"
              ],
              "query": [
                {
                  "key": "desde",
                  "value": "2026-08-01"
                },
                {
                  "key": "hasta",
                  "value": "2026-08-31"
                }
              ]
            },
            "description": "Serie de tipos de cambio entre dos fechas."
          }
        },
        {
          "name": "Euro de hoy",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/tipo-cambio?moneda=EUR",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "tipo-cambio"
              ],
              "query": [
                {
                  "key": "moneda",
                  "value": "EUR"
                }
              ]
            },
            "description": "El euro del BCRP, en soles por euro. `?moneda=EUR` vale también en la fecha, el rango y el mes. Gratis: no consume cuota."
          }
        },
        {
          "name": "Tipo de cambio de un mes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/tipo-cambio/mes/2026-09",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "tipo-cambio",
                "mes",
                "2026-09"
              ]
            },
            "description": "Las cotizaciones publicadas del mes AAAA-MM, con la respuesta del rango."
          }
        }
      ]
    },
    {
      "name": "Calendario y vencimientos SUNAT (gratis)",
      "description": "Catálogos: sin scope, sin descontar consultas y también con el token público del sandbox. Un año fuera de `meta.cubre` es 404 `anio_no_disponible`.",
      "item": [
        {
          "name": "Feriados de un año",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/calendario/feriados/2026?sector=publico",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "calendario",
                "feriados",
                "2026"
              ],
              "query": [
                {
                  "key": "sector",
                  "value": "publico"
                }
              ]
            },
            "description": "Los 16 feriados nacionales con su norma; con `sector=publico`, también los no laborables decretados."
          }
        },
        {
          "name": "¿Es hábil un día?",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/calendario/2026-07-23",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "calendario",
                "2026-07-23"
              ]
            },
            "description": "Si es hábil, por qué no y los hábiles que lo rodean."
          }
        },
        {
          "name": "Plazo en días hábiles",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/calendario/plazo?desde=2026-07-22&dias=15",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "calendario",
                "plazo"
              ],
              "query": [
                {
                  "key": "desde",
                  "value": "2026-07-22"
                },
                {
                  "key": "dias",
                  "value": "15"
                }
              ]
            },
            "description": "Cuenta desde el día siguiente a `desde` y dice qué días se saltó."
          }
        },
        {
          "name": "Cronograma SUNAT de un año",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/vencimientos/2026",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "vencimientos",
                "2026"
              ]
            },
            "description": "Los 12 periodos por último dígito del RUC y para los buenos contribuyentes (RS 281-2022/SUNAT)."
          }
        },
        {
          "name": "Lo próximo que vence",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/vencimientos/proximos?digito=5",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "vencimientos",
                "proximos"
              ],
              "query": [
                {
                  "key": "digito",
                  "value": "5"
                }
              ]
            },
            "description": "🔒 El último dígito del RUC, nunca el RUC: un `?ruc=` es 422."
          }
        }
      ]
    },
    {
      "name": "Ubigeo",
      "item": [
        {
          "name": "Ubigeo → departamento, provincia, distrito",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/ubigeo/150101",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "ubigeo",
                "150101"
              ]
            },
            "description": "El código de 6 dígitos (aquí 150101 = Lima / Lima / Lima) a sus nombres. Dato público, no exige scope."
          }
        }
      ]
    },
    {
      "name": "Watch (vigilancia de RUC)",
      "item": [
        {
          "name": "Listas de vigilancia",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/watch/listas",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "listas"
              ]
            },
            "description": "🔒 Watch solo vigila RUC tipo 20 (empresas). Requiere `watch.manage`."
          }
        },
        {
          "name": "Crear lista de vigilancia",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"nombre\": \"Mis proveedores\"\n}"
            },
            "url": {
              "raw": "{{base_url}}/watch/listas",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "listas"
              ]
            }
          }
        },
        {
          "name": "Webhooks configurados",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/watch/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "webhooks"
              ]
            },
            "description": "Los endpoints a los que se entregan los cambios, firmados."
          }
        },
        {
          "name": "Eventos de cambio",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/watch/eventos",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "eventos"
              ]
            }
          }
        },
        {
          "name": "Vigilar RUC en una lista",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/watch/listas/1/rucs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "listas",
                "1",
                "rucs"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rucs\": [\n    \"20131312955\"\n  ]\n}"
            },
            "description": "Cambia el 1 por el id de tu lista. Solo RUC 20."
          }
        },
        {
          "name": "Dejar de vigilar RUC",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/watch/listas/1/rucs",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "listas",
                "1",
                "rucs"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"rucs\": [\n    \"20131312955\"\n  ]\n}"
            }
          }
        },
        {
          "name": "Crear un webhook",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{base_url}}/watch/webhooks",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "webhooks"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://tu-sistema.pe/webhooks/nexoid\",\n  \"eventos\": [\n    \"ruc.condicion_cambiada\",\n    \"ruc.estado_cambiado\"\n  ]\n}"
            },
            "description": "Solo https. El secreto para verificar la firma se ve una vez, en la respuesta."
          }
        },
        {
          "name": "Probar un webhook",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{base_url}}/watch/webhooks/1/probar",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "watch",
                "webhooks",
                "1",
                "probar"
              ]
            },
            "description": "Cambia el 1 por el id de tu webhook."
          }
        }
      ],
      "description": "403 `no_disponible_en_sandbox` con un token de prueba: vigila RUC reales. Hace falta un token live con `watch.manage`."
    }
  ]
}
