{"_id":"@apifycr/connect","name":"@apifycr/connect","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@apifycr/connect","version":"0.1.0","description":"SDK oficial de Node.js para la API TSE v2 de ApifyConnect. Consulta de cédulas, personas y empresas en Costa Rica.","license":"UNLICENSED","author":{"name":"ApifyCR"},"homepage":"https://tse.apifycr.com","bugs":{"url":"https://tse.apifycr.com"},"repository":{"type":"git","url":"https://tse.apifycr.com"},"keywords":["apifycr","tse","costa-rica","cedula","padron-electoral","api","sdk","typescript"],"sideEffects":false,"type":"module","main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"}},"engines":{"node":">=18"},"scripts":{"build":"tsup","clean":"rimraf dist","typecheck":"tsc --noEmit","lint":"biome check src tests","format":"biome format --write src tests","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run clean && npm run typecheck && npm run lint && npm run test && npm run build"},"devDependencies":{"@biomejs/biome":"^1.9.0","@types/node":"^22.15.29","rimraf":"^6.0.1","tsup":"^8.5.0","typescript":"^5.8.3","vitest":"^2.0.0"},"_id":"@apifycr/connect@0.1.0","_nodeVersion":"22.19.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-A8pmBn2HhbvqEYeiQMmJwqZtegKlV6LqQvniM/XMZ+7YWLcskY2ueNP00c+HAVpSloa0aYubfrLht9VafgDKFg==","shasum":"d4ed3b64e9ffdcf8060e2720102f20ba4b517b0e","tarball":"https://registry.npmjs.org/@apifycr/connect/-/connect-0.1.0.tgz","fileCount":9,"unpackedSize":156981,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBn810WEuMxcKmwljtWsQj3gjWSt33r4edaCkAy/AEqWAiBWhwoUNdwBpvyzENemrc4FnqWrecot7onUQZibItYqIw=="}]},"_npmUser":{"name":"apifycr","email":"info@apifycr.com"},"directories":{},"maintainers":[{"name":"apifycr","email":"info@apifycr.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/connect_0.1.0_1778108044787_0.20631883405074225"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-06T22:54:04.724Z","0.1.0":"2026-05-06T22:54:04.950Z","modified":"2026-05-06T22:54:05.502Z"},"maintainers":[{"name":"apifycr","email":"info@apifycr.com"}],"description":"SDK oficial de Node.js para la API TSE v2 de ApifyConnect. Consulta de cédulas, personas y empresas en Costa Rica.","homepage":"https://tse.apifycr.com","keywords":["apifycr","tse","costa-rica","cedula","padron-electoral","api","sdk","typescript"],"repository":{"type":"git","url":"https://tse.apifycr.com"},"author":{"name":"ApifyCR"},"bugs":{"url":"https://tse.apifycr.com"},"license":"UNLICENSED","readme":"# `@apifycr/connect`\n\nSDK oficial de Node.js para la **API TSE v2 de ApifyConnect**.\n\n- URL base: `https://tse.apifycr.com/api/v2`\n- Autenticación: `Authorization: Bearer <api_key>`\n- Requiere una cuenta activa en [tse.apifycr.com](https://tse.apifycr.com).\n\n---\n\n## Tabla de contenidos\n\n1. [Instalación](#instalación)\n2. [Inicio rápido](#inicio-rápido)\n3. [Configuración del cliente](#configuración-del-cliente)\n4. [Endpoints](#endpoints)\n   - [getByCedula — consulta por cédula](#getbycedula--consulta-por-cédula)\n   - [searchPersona — búsqueda por nombre](#searchpersona--búsqueda-por-nombre)\n   - [iteratePersona — recorrer todas las páginas](#iteratepersona--recorrer-todas-las-páginas)\n   - [getJuridica — persona jurídica](#getjuridica--persona-jurídica)\n5. [Clase `Persona`](#clase-persona)\n   - [Identidad](#identidad)\n   - [Fechas](#fechas)\n   - [Edad](#edad)\n   - [Estado](#estado)\n   - [Ubicación electoral](#ubicación-electoral)\n   - [Padres](#padres)\n   - [Selección de campos — `.only()`](#selección-de-campos--only)\n   - [Registro crudo — `.toPlain()`](#registro-crudo--toplain)\n6. [Clase `Juridica`](#clase-juridica)\n7. [Manejo de errores](#manejo-de-errores)\n8. [Rate limiting](#rate-limiting)\n9. [Hooks de observabilidad](#hooks-de-observabilidad)\n10. [Seguridad y buenas prácticas](#seguridad-y-buenas-prácticas)\n11. [Uso en frameworks](#uso-en-frameworks)\n\n---\n\n## Instalación\n\n```bash\nnpm install @apifycr/connect\n```\n\nRequiere **Node.js 18 o superior**.\n\n---\n\n## Inicio rápido\n\n```ts\nimport { createApifyConnectClient } from \"@apifycr/connect\";\n\nconst client = createApifyConnectClient({\n  apiKey: process.env.APIFYCR_API_KEY!,\n});\n\nconst persona = await client.getByCedula({ cedula: \"123456789\" });\n\nconsole.log(persona.fullName);          // \"PABLO VERA QUESADA\"\nconsole.log(persona.nombreFormateado);  // \"Pablo Vera Quesada\"\nconsole.log(persona.cedulaFormateada);  // \"1-2345-6789\"\nconsole.log(persona.edad());            // \"30 años 5 meses\"\nconsole.log(persona.direccionElectoral); // \"Brasil, Santa Ana, San José\"\n```\n\n---\n\n## Configuración del cliente\n\n```ts\nconst client = createApifyConnectClient({\n  apiKey: \"...\",          // Requerido. Su API key de ApifyConnect.\n  timeoutMs: 20_000,      // Opcional. Timeout en ms (defecto: 20 000).\n  baseUrl: \"...\",         // Opcional. Sobreescribe la URL base (para pruebas).\n  userAgent: \"mi-app/1\", // Opcional. Se añade al encabezado User-Agent.\n  allowBrowser: false,    // Opcional. Ver sección de seguridad.\n  onRequest: (e) => {},   // Opcional. Hook de observabilidad (ver más abajo).\n  onResponse: (e) => {},\n  onError: (e) => {},\n});\n```\n\n### Protección de la API key en el navegador\n\nPor defecto el SDK **bloquea su uso en el navegador** para evitar exponer la clave accidentalmente. Si hace llamadas desde su propio backend, no necesita ningún ajuste.\n\nSi por alguna razón necesita llamar desde el cliente (SPA, extensión de Chrome, etc.), debe optar explícitamente:\n\n```ts\nconst client = createApifyConnectClient({\n  apiKey: process.env.APIFYCR_API_KEY!,\n  allowBrowser: true, // ⚠️ Expone la API key al usuario final\n});\n```\n\n---\n\n## Endpoints\n\n### `getByCedula` — consulta por cédula\n\nRetorna una instancia de [`Persona`](#clase-persona) con todos los campos del API y propiedades computadas adicionales.\n\n```ts\nconst persona = await client.getByCedula({ cedula: \"123456789\" });\n```\n\n| Parámetro | Tipo     | Descripción                       |\n|-----------|----------|-----------------------------------|\n| `cedula`  | `string` | Cédula de 9 dígitos (solo números). |\n\n---\n\n### `searchPersona` — búsqueda por nombre\n\nBusca personas por nombre y apellidos. El nombre acepta coincidencia parcial. Retorna un resultado paginado con instancias de `Persona`.\n\n```ts\nconst result = await client.searchPersona({\n  nombre: \"pablo\",\n  apellido: \"vera\",\n  apellido2: \"quesada\", // opcional\n  page: 1,              // opcional, defecto: 1\n});\n\nconsole.log(result.total);       // 16\nconsole.log(result.last_page);   // 2\nconsole.log(result.data);        // Persona[]\n\nfor (const persona of result.data) {\n  console.log(persona.nombreFormateado, persona.edad());\n}\n\n// Siguiente página\nif (result.next_page_url) {\n  const page2 = await client.searchPersona({ nombre: \"pablo\", apellido: \"vera\", page: 2 });\n}\n```\n\n| Parámetro   | Tipo     | Requerido | Descripción                         |\n|-------------|----------|-----------|-------------------------------------|\n| `nombre`    | `string` | Sí        | Nombre o parte del nombre.          |\n| `apellido`  | `string` | Sí        | Primer apellido (exacto).           |\n| `apellido2` | `string` | No        | Segundo apellido (exacto).          |\n| `page`      | `number` | No        | Número de página. Defecto: 1.       |\n\n**Paginación** — la respuesta incluye `current_page`, `last_page`, `total`, `per_page` (fijo en 15), `next_page_url` y `prev_page_url`.\n\n---\n\n### `iteratePersona` — recorrer todas las páginas\n\nGenera automáticamente todas las páginas y las recorre una a una. Ideal para exportaciones o búsquedas que devuelven muchos resultados.\n\n```ts\nfor await (const persona of client.iteratePersona({ nombre: \"pablo\", apellido: \"vera\" })) {\n  console.log(persona.cedulaFormateada, persona.fullName);\n}\n```\n\n> Cada iteración hace una llamada al API. Tenga en cuenta los [límites de uso](#rate-limiting).\n\n---\n\n### `getJuridica` — persona jurídica\n\nRetorna una instancia de [`Juridica`](#clase-juridica).\n\n```ts\nconst empresa = await client.getJuridica({ cedula: \"1234567890\" });\n\nconsole.log(empresa.nombre);           // \"APIFY LATAM SOCIEDAD ANONIMA\"\nconsole.log(empresa.nombreFormateado); // \"Apify Latam Sociedad Anonima\"\nconsole.log(empresa.tipoNombre);       // \"Cédula Jurídica\"\n```\n\n| Parámetro | Tipo     | Descripción                          |\n|-----------|----------|--------------------------------------|\n| `cedula`  | `string` | Cédula jurídica de 10 dígitos.       |\n\n---\n\n## Clase `Persona`\n\nTodos los campos crudos del API siguen disponibles directamente (`persona.nombre`, `persona.cedula`, etc.). La clase añade las siguientes propiedades y métodos computados.\n\n### Identidad\n\n| Propiedad          | Tipo     | Ejemplo                    | Descripción                                      |\n|--------------------|----------|----------------------------|--------------------------------------------------|\n| `fullName`         | `string` | `\"PABLO VERA QUESADA\"`     | Nombre completo en mayúsculas.                   |\n| `nombreFormateado` | `string` | `\"Pablo Vera Quesada\"`     | Nombre completo en formato título.               |\n| `cedulaFormateada` | `string` | `\"1-2345-6789\"`            | Cédula en formato estándar costarricense.        |\n\n```ts\npersona.fullName          // \"PABLO VERA QUESADA\"\npersona.nombreFormateado  // \"Pablo Vera Quesada\"\npersona.cedulaFormateada  // \"1-2345-6789\"\n```\n\n---\n\n### Fechas\n\nEl API devuelve `fecha_nacimiento` en formato `DD/MM/YYYY` y `fecha_caduc` en `YYYYMMDD`. El SDK los parsea correctamente a instancias de `Date` listas para usar.\n\n> **No use `new Date(persona.fecha_nacimiento)` directamente** — el formato `DD/MM/YYYY` no es reconocido de forma consistente por todos los motores de JavaScript y puede producir fechas incorrectas o `Invalid Date`.\n\n| Propiedad        | Tipo           | Descripción                                         |\n|------------------|----------------|-----------------------------------------------------|\n| `fechaNacimiento`| `Date \\| null` | Fecha de nacimiento. Parseada desde `DD/MM/YYYY`.   |\n| `fechaCaducidad` | `Date \\| null` | Caducidad de la cédula. Parseada desde `YYYYMMDD`.  |\n\n```ts\nconst fn = persona.fechaNacimiento;\nif (fn) {\n  console.log(fn.getFullYear()); // 1995\n  console.log(fn.toLocaleDateString(\"es-CR\")); // \"11/4/1995\"\n}\n\nconst fc = persona.fechaCaducidad;\nif (fc && fc < new Date()) {\n  console.log(\"Cédula vencida\");\n}\n```\n\n---\n\n### Edad\n\n```ts\npersona.edad()   // \"30 años 5 meses\"   (defecto: 2 partes)\npersona.edad(1)  // \"30 años\"\npersona.edad(2)  // \"30 años 5 meses\"\npersona.edad(3)  // \"30 años 5 meses 12 días\"\n```\n\nRetorna `\"Fecha de nacimiento desconocida\"` si `fecha_nacimiento` es null.\n\n---\n\n### Estado\n\n| Propiedad       | Tipo      | Descripción                                                              |\n|-----------------|-----------|--------------------------------------------------------------------------|\n| `isEmpadronado` | `boolean` | `true` si la persona tiene `codelec` (está inscrita en el padrón).      |\n| `isMenorDeEdad` | `boolean` | `true` si es menor de 18 años. `false` si la fecha de nacimiento es null.|\n\n```ts\nif (!persona.isEmpadronado) {\n  console.log(\"Persona no empadronada (posible menor de edad u otro)\");\n}\n\nif (persona.isMenorDeEdad) {\n  console.log(\"Acceso restringido: menor de edad\");\n}\n```\n\n---\n\n### Ubicación electoral\n\nLos campos `provincia`, `canton` y `distrito` son null cuando `codelec` es null (persona no empadronada).\n\n| Propiedad             | Tipo                                              | Ejemplo               |\n|-----------------------|---------------------------------------------------|-----------------------|\n| `provincia`           | `string \\| null`                                  | `\"SAN JOSE\"`          |\n| `canton`              | `string \\| null`                                  | `\"SANTA ANA\"`         |\n| `distrito`            | `string \\| null`                                  | `\"BRASIL\"`            |\n| `provinciaFormateada` | `string \\| null`                                  | `\"San Jose\"`          |\n| `cantonFormateado`    | `string \\| null`                                  | `\"Santa Ana\"`         |\n| `distritoFormateado`  | `string \\| null`                                  | `\"Brasil\"`            |\n| `location`            | `{ provincia, canton, distrito } \\| null`         | Objeto en mayúsculas  |\n| `locationFormateada`  | `{ provincia, canton, distrito } \\| null`         | Objeto en título      |\n| `direccionElectoral`  | `string \\| null`                                  | `\"Brasil, Santa Ana, San Jose\"` |\n\n```ts\n// Acceso individual\nconsole.log(persona.provincia);           // \"SAN JOSE\"\nconsole.log(persona.provinciaFormateada); // \"San Jose\"\nconsole.log(persona.canton);              // \"SANTA ANA\"\nconsole.log(persona.cantonFormateado);    // \"Santa Ana\"\nconsole.log(persona.distrito);            // \"BRASIL\"\nconsole.log(persona.distritoFormateado);  // \"Brasil\"\n\n// Objeto completo\nconsole.log(persona.location);\n// { provincia: \"SAN JOSE\", canton: \"SANTA ANA\", distrito: \"BRASIL\" }\n\nconsole.log(persona.locationFormateada);\n// { provincia: \"San Jose\", canton: \"Santa Ana\", distrito: \"Brasil\" }\n\n// Una sola línea\nconsole.log(persona.direccionElectoral);\n// \"Brasil, Santa Ana, San Jose\"\n\n// Guarda con null check\nif (persona.location) {\n  mostrarMapa(persona.location.provincia, persona.location.canton);\n}\n```\n\n---\n\n### Padres\n\n| Propiedad       | Tipo             | Ejemplo           |\n|-----------------|------------------|-------------------|\n| `padre`         | `string \\| null` | `\"JUAN VERA\"`     |\n| `madre`         | `string \\| null` | `\"MARIA QUESADA\"` |\n| `padreFormateado`| `string \\| null`| `\"Juan Vera\"`     |\n| `madreFormateado`| `string \\| null`| `\"Maria Quesada\"` |\n\n```ts\nconsole.log(persona.padreFormateado); // \"Juan Vera\"\nconsole.log(persona.madreFormateado); // \"Maria Quesada\"\n```\n\n---\n\n### Selección de campos — `.only()`\n\nRetorna un objeto plano con únicamente los campos solicitados. Útil para construir respuestas de API propias, logs o formularios sin exponer datos innecesarios.\n\nAcepta tanto campos crudos del API como cualquiera de los campos computados listados arriba.\n\n```ts\n// Solo nombre y cédula\npersona.only(['nombre', 'apellido1', 'cedula'])\n// → { nombre: 'PABLO', apellido1: 'VERA', cedula: '123456789' }\n\npersona.only(['nombreFormateado', 'cedulaFormateada', 'fechaNacimiento'])\n\n// Respuesta ligera para una API propia\nconst payload = persona.only([\n  'cedulaFormateada',\n  'nombreFormateado',\n  'direccionElectoral',\n  'isEmpadronado',\n  'isMenorDeEdad',\n]);\nres.json(payload);\n```\n\n**Campos disponibles en `.only()`:**\n\nTodos los campos crudos del API (`cedula`, `codelec`, `fecha_caduc`, `nombre`, `apellido1`, `apellido2`, `fecha_nacimiento`, `padre`, `cedula_padre`, `madre`, `cedula_madre`, `provincia`, `canton`, `distrito`) más los computados:\n\n`fullName` · `nombreFormateado` · `cedulaFormateada` · `fechaNacimiento` · `fechaCaducidad` · `isEmpadronado` · `isMenorDeEdad` · `provinciaFormateada` · `cantonFormateado` · `distritoFormateado` · `location` · `locationFormateada` · `direccionElectoral` · `padreFormateado` · `madreFormateado`\n\n---\n\n### Registro crudo — `.toPlain()`\n\nRetorna el objeto original tal como lo devolvió el API, sin propiedades computadas. Útil para serializar, almacenar en base de datos o pasar a librerías que no aceptan instancias de clase.\n\n```ts\nconst raw = persona.toPlain();\nawait db.insert(\"personas\", raw);\n```\n\n---\n\n## Clase `Juridica`\n\n| Propiedad          | Tipo     | Ejemplo                          | Descripción                        |\n|--------------------|----------|----------------------------------|------------------------------------|\n| `nombre`           | `string` | `\"APIFY LATAM SOCIEDAD ANONIMA\"` | Razón social en mayúsculas.        |\n| `tipoIdentificacion`| `string`| `\"02\"`                           | Código de tipo del API.            |\n| `nombreFormateado` | `string` | `\"Apify Latam Sociedad Anonima\"` | Razón social en formato título.    |\n| `tipoNombre`       | `string` | `\"Cédula Jurídica\"`              | Descripción legible del tipo.      |\n\n```ts\nconst empresa = await client.getJuridica({ cedula: \"1234567890\" });\n\nempresa.nombre            // \"APIFY LATAM SOCIEDAD ANONIMA\"\nempresa.nombreFormateado  // \"Apify Latam Sociedad Anonima\"\nempresa.tipoIdentificacion // \"02\"\nempresa.tipoNombre        // \"Cédula Jurídica\"\n\nconst raw = empresa.toPlain();\n// { nombre: \"APIFY LATAM SOCIEDAD ANONIMA\", tipoIdentificacion: \"02\" }\n```\n\n**Tipos soportados en `tipoNombre`:**\n\n| Código | Nombre                  |\n|--------|-------------------------|\n| `01`   | Cédula de Identidad     |\n| `02`   | Cédula Jurídica         |\n| `03`   | DIMEX                   |\n| `04`   | NITE                    |\n\n---\n\n## Manejo de errores\n\nEl SDK lanza `ApifyConnectError` para cualquier respuesta que no sea 2xx.\n\n```ts\nimport { ApifyConnectError } from \"@apifycr/connect\";\n\ntry {\n  const persona = await client.getByCedula({ cedula: \"000000000\" });\n} catch (error) {\n  if (error instanceof ApifyConnectError) {\n    console.error(error.status);                    // 404\n    console.error(error.data?.error);               // \"Persona no encontrada.\"\n    console.error(error.rateLimit.retryAfterSeconds); // undefined (o segundos si fue 429)\n  }\n}\n```\n\n| Propiedad                        | Tipo              | Descripción                                         |\n|----------------------------------|-------------------|-----------------------------------------------------|\n| `error.status`                   | `number`          | Código HTTP (404, 401, 429, etc.).                  |\n| `error.statusText`               | `string`          | Texto del status HTTP.                              |\n| `error.data`                     | `object \\| null`  | Cuerpo JSON de la respuesta de error.               |\n| `error.data?.error`              | `string \\| undefined` | Mensaje de error del API.                       |\n| `error.rateLimit.limit`          | `number \\| undefined` | Límite de solicitudes de la ventana.            |\n| `error.rateLimit.remaining`      | `number \\| undefined` | Solicitudes restantes.                          |\n| `error.rateLimit.retryAfterSeconds` | `number \\| undefined` | Segundos a esperar antes de reintentar (429). |\n\n**Tabla de códigos de error del API:**\n\n| Código | Significado             | Facturable | Descripción                                      |\n|--------|-------------------------|------------|--------------------------------------------------|\n| `401`  | No autorizado           | No         | API key inválida o ausente.                      |\n| `403`  | Suscripción / CORS      | Sí         | Sin suscripción activa o dominio no permitido.   |\n| `404`  | No encontrado           | Sí         | Cédula sin resultados.                           |\n| `422`  | Parámetros inválidos    | Sí         | `cedula` ausente o con formato incorrecto.       |\n| `429`  | Límite superado         | Sí         | Demasiadas solicitudes. Ver `Retry-After`.       |\n| `500`  | Error interno           | No         | Error del servidor de ApifyConnect.              |\n| `502`  | Bad Gateway             | No         | Error temporal en servicio upstream.             |\n| `503`  | Service Unavailable     | No         | Servicio no disponible temporalmente.            |\n\n---\n\n## Rate limiting\n\nEl API v2 aplica los siguientes límites por cuenta:\n\n- **1 solicitud** cada 5 segundos\n- **12 solicitudes** por minuto\n- **1 000 solicitudes** por día\n\nCuando se supera el límite el API responde `429 Too Many Requests` con el encabezado `Retry-After` indicando cuántos segundos esperar.\n\n```ts\ntry {\n  await client.getByCedula({ cedula: \"123456789\" });\n} catch (error) {\n  if (error instanceof ApifyConnectError && error.status === 429) {\n    const wait = error.rateLimit.retryAfterSeconds ?? 5;\n    console.log(`Límite alcanzado. Reintente en ${wait} segundos.`);\n  }\n}\n```\n\nLas respuestas exitosas incluyen los encabezados `X-RateLimit-Limit` y `X-RateLimit-Remaining`, accesibles a través del hook `onResponse` (ver abajo).\n\n---\n\n## Hooks de observabilidad\n\nLos hooks permiten integrar el SDK con su sistema de logging, métricas o trazabilidad sin modificar la lógica de negocio.\n\n```ts\nconst client = createApifyConnectClient({\n  apiKey: process.env.APIFYCR_API_KEY!,\n\n  onRequest: ({ method, url, redactedHeaders }) => {\n    // Usar redactedHeaders para no loguear la API key\n    console.log(`→ ${method} ${url}`, redactedHeaders);\n  },\n\n  onResponse: ({ status, url, rateLimit }) => {\n    console.log(`← ${status} ${url}`, {\n      remaining: rateLimit.remaining,\n      limit: rateLimit.limit,\n    });\n  },\n\n  onError: ({ url, error }) => {\n    console.error(`✗ ${url}`, error);\n  },\n});\n```\n\n> **Importante:** use siempre `redactedHeaders` (no `headers`) en `onRequest` para evitar que la API key aparezca en logs.\n\n---\n\n## Seguridad y buenas prácticas\n\n- Guarde la API key en variables de entorno (`process.env.APIFYCR_API_KEY`) o en un gestor de secretos (AWS Secrets Manager, Doppler, etc.).\n- Nunca incluya la clave en código fuente, repositorios públicos ni respuestas de su API.\n- Llame al API desde su **backend**, no desde el navegador. Así la clave nunca llega al usuario final.\n- Si usa el hook `onRequest`, registre `redactedHeaders`, no `headers`.\n- Rote y revoque claves comprometidas desde el dashboard de su cuenta.\n\n---\n\n## Uso en frameworks\n\n### Express / Node.js\n\n```ts\nimport express from \"express\";\nimport { createApifyConnectClient, ApifyConnectError } from \"@apifycr/connect\";\n\nconst client = createApifyConnectClient({ apiKey: process.env.APIFYCR_API_KEY! });\nconst app = express();\n\napp.get(\"/api/persona/:cedula\", async (req, res) => {\n  try {\n    const persona = await client.getByCedula({ cedula: req.params.cedula });\n    res.json(persona.only([\n      \"cedulaFormateada\",\n      \"nombreFormateado\",\n      \"fechaNacimiento\",\n      \"direccionElectoral\",\n    ]));\n  } catch (error) {\n    if (error instanceof ApifyConnectError) {\n      res.status(error.status).json({ error: error.data?.error ?? error.message });\n    } else {\n      res.status(500).json({ error: \"Error interno\" });\n    }\n  }\n});\n```\n\n### Next.js (App Router)\n\n```ts\n// app/api/cedula/route.ts\nimport { NextRequest, NextResponse } from \"next/server\";\nimport { createApifyConnectClient, ApifyConnectError } from \"@apifycr/connect\";\n\nconst client = createApifyConnectClient({ apiKey: process.env.APIFYCR_API_KEY! });\n\nexport async function GET(req: NextRequest) {\n  const cedula = req.nextUrl.searchParams.get(\"cedula\") ?? \"\";\n  try {\n    const persona = await client.getByCedula({ cedula });\n    return NextResponse.json({\n      nombre: persona.nombreFormateado,\n      cedula: persona.cedulaFormateada,\n      edad: persona.edad(),\n      ubicacion: persona.direccionElectoral,\n    });\n  } catch (error) {\n    if (error instanceof ApifyConnectError) {\n      return NextResponse.json(\n        { error: error.data?.error ?? error.message },\n        { status: error.status },\n      );\n    }\n    return NextResponse.json({ error: \"Error interno\" }, { status: 500 });\n  }\n}\n```\n\n### Verificación de mayoría de edad\n\n```ts\nconst persona = await client.getByCedula({ cedula: req.body.cedula });\n\nif (persona.isMenorDeEdad) {\n  return res.status(403).json({ error: \"Acceso restringido a mayores de edad.\" });\n}\n\n// Continuar con el flujo...\n```\n\n### Exportar todos los resultados de una búsqueda\n\n```ts\nconst resultados: object[] = [];\n\nfor await (const persona of client.iteratePersona({ nombre: \"maria\", apellido: \"rodriguez\" })) {\n  resultados.push(persona.only([\n    \"cedulaFormateada\",\n    \"nombreFormateado\",\n    \"provinciaFormateada\",\n    \"cantonFormateado\",\n    \"fechaNacimiento\",\n  ]));\n}\n\nawait fs.writeFile(\"resultados.json\", JSON.stringify(resultados, null, 2));\n```\n\n---\n\n## Sitio web\n\n[https://tse.apifycr.com](https://tse.apifycr.com)\n","readmeFilename":"README.md","_rev":"1-8bde8f3485be65fc30ea84e93de90bd3"}