{
  "info": {
    "name": "Identik API — Integración de clientes",
    "description": "Flujo completo para crear y enviar documentos a firmar vía la API de Identik.\n\n## Plataformas\n- **firma.identik.me** → firma DIGITAL (Digilogix, Ley 25.506 arts. 2/7/8). El CUIL de cada firmante es OBLIGATORIO.\n- **electronica.identik.me** → firma ELECTRÓNICA (Ley 25.506, art. 5, click-to-sign). El CUIL NO se usa.\n\nTu API token pertenece a UNA plataforma: configurá `baseUrl` + `apiToken` en las variables de la colección (o en un Environment).\n\n## Flujo (en orden)\n1. **Crear documento** → devuelve `documentId`, `uploadUrl` (URL prefirmada) y los firmantes con su `signingUrl`.\n2. **Subir el PDF** → PUT binario a `uploadUrl`.\n3. **Agregar campos de firma** → coordenadas en % de la página (un campo SIGNATURE por firmante).\n4. **Enviar** → cada firmante recibe el email con su enlace único (o usá `sendEmail:false` y distribuí los `signingUrl` vos).\n5. **Consultar estado** → hasta `status: COMPLETED`.\n6. **Descargar el firmado** → PDF sellado. En electrónica la constancia va integrada al final del mismo PDF; en digital llega como adjunto aparte en el email de completado.\n\n## Cupo mensual\nTu organización tiene un tope de documentos por mes (plan). Si lo alcanzás, `POST /documents` devuelve **400** con `\"Alcanzaste el máximo de documentos de tu plan para este mes.\"`. La facturación es a mes vencido por uso real.\n\n## OpenAPI\n- `{{baseUrl}}/api/v1/openapi.json` (esta colección)\n- `{{baseUrl}}/api/v2/openapi.json` (API v2)\n\n## Límites de uso\nHasta **100 solicitudes por minuto por IP**. Superado el límite: `429` + encabezado `Retry-After` (segundos). Cada respuesta trae `X-RateLimit-Limit` / `X-RateLimit-Remaining` / `X-RateLimit-Reset`.\n\n## Verificación biométrica (solo electronica.identik.me)\nPara exigir DNI + prueba de vida facial antes de firmar, mandá `\"meta\": { \"requireBiometricId\": true }` en el paso 1 (crear documento) o en `generate-document` desde plantilla. Cada verificación aprobada consume 1 crédito del pool prepago de la cuenta; sin créditos, el firmante firma normalmente. El resto del circuito (signingUrl, webhooks, descarga) no cambia.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://electronica.identik.me",
      "description": "https://firma.identik.me (digital) o https://electronica.identik.me (electrónica)"
    },
    {
      "key": "apiToken",
      "value": "api_XXXXXXXXXXXX",
      "description": "Tu token (te lo entrega Identik). Va como Authorization: Bearer."
    },
    {
      "key": "documentId",
      "value": "",
      "description": "Se completa solo al correr el paso 1."
    },
    {
      "key": "uploadUrl",
      "value": "",
      "description": "Se completa solo al correr el paso 1."
    },
    {
      "key": "recipientId1",
      "value": "",
      "description": "recipientId del firmante 1 (lo setea el paso 1)."
    },
    {
      "key": "recipientId2",
      "value": "",
      "description": "recipientId del firmante 2 (lo setea el paso 1)."
    },
    {
      "key": "envelopeId",
      "value": "",
      "type": "string"
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiToken}}",
        "type": "string"
      }
    ]
  },
  "item": [
    {
      "name": "1 · Crear documento",
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const j = pm.response.json();",
              "pm.test('201/200 y documentId presente', () => pm.expect(j.documentId).to.be.a('number'));",
              "pm.collectionVariables.set('documentId', j.documentId);",
              "pm.collectionVariables.set('uploadUrl', j.uploadUrl);",
              "if (j.recipients?.[0]) pm.collectionVariables.set('recipientId1', j.recipients[0].recipientId);",
              "if (j.recipients?.[1]) pm.collectionVariables.set('recipientId2', j.recipients[1].recipientId);",
              "console.log('signingUrls:', (j.recipients||[]).map(r => r.signingUrl));"
            ]
          }
        }
      ],
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseUrl}}/api/v1/documents",
        "description": "Crea el documento y declara los firmantes.\n\n- `title`: nombre del documento (aparece en emails y en la constancia).\n- `recipients[]`: `name`, `email` y — SOLO en la plataforma digital — `cuil` (11 dígitos; se aceptan guiones/espacios).\n\nRespuesta: `documentId`, `uploadUrl` (subí el PDF ahí en el paso 2) y `recipients[]` con `recipientId`, `token` y `signingUrl` de cada firmante.\n\n⚠️ Si tu plan mensual está completo, acá recibís 400 con el mensaje de cupo.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"title\": \"Contrato de servicios\",\n  \"recipients\": [\n    { \"name\": \"Juan Pérez\", \"email\": \"juan@cliente.com.ar\" },\n    { \"name\": \"María Gómez\", \"email\": \"maria@cliente.com.ar\" }\n  ]\n}\n\n// Plataforma DIGITAL (firma.identik.me): agregá el CUIL a cada firmante:\n// { \"name\": \"Juan Pérez\", \"email\": \"juan@...\", \"cuil\": \"20-33111349-3\" }\n\n// Plataforma ELECTRÓNICA (electronica.identik.me): para exigir verificación\n// biométrica (DNI + prueba de vida) antes de firmar, agregá:\n//   \"meta\": { \"requireBiometricId\": true }\n// y fijá la identidad esperada en cada firmante (recomendado — la verificación\n// se valida CONTRA estos datos; nombre y apellido van POR SEPARADO):\n//   { \"name\": \"...\", \"email\": \"...\", \"idDocumentNumber\": \"33111349\",\n//     \"firstName\": \"Juan\", \"lastName\": \"Pérez\" }\n// Consume 1 crédito prepago por verificación; sin créditos, se firma normalmente."
        }
      }
    },
    {
      "name": "2 · Subir el PDF (PUT a uploadUrl)",
      "request": {
        "method": "PUT",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/pdf"
          }
        ],
        "url": "{{uploadUrl}}",
        "description": "Subí el PDF con un PUT **binario** a la URL prefirmada del paso 1 (Body → binary → seleccioná el archivo).\n\n- La URL ya está autenticada: NO agregues el header Authorization (Postman lo hereda de la colección — desactivalo en Auth → No Auth para este request).\n- Respuesta esperada: 200 sin cuerpo.",
        "auth": {
          "type": "noauth"
        },
        "body": {
          "mode": "file",
          "file": {}
        }
      }
    },
    {
      "name": "3a · Campo de firma — firmante 1",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseUrl}}/api/v1/documents/{{documentId}}/fields",
        "description": "Coloca el campo de firma del firmante 1 en la página.\n\nCoordenadas en **porcentaje de la página** (origen arriba-izquierda):\n- `pageNumber`: 1-based.\n- `pageX`/`pageY`: esquina superior izquierda del campo (%).\n- `pageWidth`/`pageHeight`: tamaño del campo (%).\n\nEl dibujo de la firma queda EXACTAMENTE en esas coordenadas en el PDF final.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"recipientId\": {{recipientId1}},\n  \"type\": \"SIGNATURE\",\n  \"pageNumber\": 1,\n  \"pageX\": 18,\n  \"pageY\": 55,\n  \"pageWidth\": 24,\n  \"pageHeight\": 6\n}"
        }
      }
    },
    {
      "name": "3b · Campo de firma — firmante 2",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseUrl}}/api/v1/documents/{{documentId}}/fields",
        "description": "Igual que 3a, para el segundo firmante (otra posición para que no se pisen).",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"recipientId\": {{recipientId2}},\n  \"type\": \"SIGNATURE\",\n  \"pageNumber\": 1,\n  \"pageX\": 18,\n  \"pageY\": 72,\n  \"pageWidth\": 24,\n  \"pageHeight\": 6\n}"
        }
      }
    },
    {
      "name": "4 · Enviar a firmar",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ],
        "url": "{{baseUrl}}/api/v1/documents/{{documentId}}/send",
        "description": "Dispara el envío.\n\n- `sendEmail: true` → Identik le manda a cada firmante el email con su enlace único.\n- `sendEmail: false` → no se manda nada: distribuís vos los `signingUrl` del paso 1 (por tu propio canal).\n\nEn la plataforma ELECTRÓNICA el firmante abre el enlace, revisa y confirma (menos de 2 minutos). En la DIGITAL, además autoriza con su CUIL + PIN + OTP ante el certificador.",
        "body": {
          "mode": "raw",
          "raw": "{\n  \"sendEmail\": true\n}"
        }
      }
    },
    {
      "name": "5 · Consultar estado",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/api/v1/documents/{{documentId}}",
        "description": "Estado del documento: `PENDING` (esperando firmas) → `COMPLETED` (todos firmaron y el PDF quedó sellado).\n\nMejor que polling: configurá un **webhook** `DOCUMENT_COMPLETED` (Configuración del equipo → Webhooks) y recibís el aviso con el documento apenas se completa."
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "const j = pm.response.json();",
              "pm.test('200 y status presente', () => pm.expect(j.status).to.be.a('string'));",
              "// El envelopeId solo aparece anidado en fields[]: es lo que piden los endpoints v2.",
              "const envelopeId = j.fields?.[0]?.envelopeId;",
              "if (envelopeId) { pm.collectionVariables.set('envelopeId', envelopeId); }",
              "else { console.warn('Sin campos todavia: el envelopeId no esta disponible (paso 8 va a fallar).'); }",
              "console.log('status:', j.status, '| firmantes:', (j.recipients||[]).map(r => r.email + ':' + r.signingStatus));"
            ]
          }
        }
      ]
    },
    {
      "name": "6 · Descargar el PDF firmado",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/api/v1/documents/{{documentId}}/download",
        "description": "Devuelve la URL de descarga del PDF firmado y sellado.\n\nLa **Constancia de firma** (cada firmante, marcas temporales y hash SHA-256): en **electrónica** va integrada como última página del PDF; en **digital** llega como adjunto aparte (`Constancia de firma.pdf`) en el email de completado, para no invalidar la firma cualificada. Cualquiera puede verificar el documento en `{{baseUrl}}/validar`."
      }
    },
    {
      "name": "7 · Descargar el PDF (bytes directos, v2)",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/api/v2/document/{{documentId}}/download?version=signed",
        "description": "Alternativa al paso 6: devuelve directamente los **bytes del PDF** (`application/pdf`) en lugar de una URL de descarga. Suele ser mas comodo para guardar el archivo desde el backend sin un segundo salto.\n\n`version=signed` (por defecto) trae el documento firmado; `version=original`, el PDF tal como se subio.\n\nAcepta **tanto el `id` numerico** del documento (igual que v1) **como su `envelopeId`** (`envelope_...`) en el mismo lugar de la URL. Funciona con documentos creados por esta API.\n\nPasado el plazo de resguardo el archivo ya no existe y responde `410`."
      }
    },
    {
      "name": "8 · Traza de auditoria (v2)",
      "request": {
        "method": "GET",
        "url": "{{baseUrl}}/api/v2/envelope/{{envelopeId}}/audit-log?page=1&perPage=50",
        "description": "Devuelve la traza de auditoria en JSON: creacion, envio, apertura, firma de cada campo, rechazo y finalizacion, con fecha, IP y dispositivo. Sirve para archivar la evidencia de forma estructurada, ademas del PDF.\n\n⚠️ Identifica el documento con el **`envelopeId`** (`envelope_...`), NO con el `id` numerico: mandarle el numero devuelve `400 Invalid envelope ID`. El paso 5 lo captura automaticamente desde `fields[].envelopeId`."
      }
    }
  ]
}