# Cómo hacer que tu plataforma se conecte con jnfor en un clic

Cualquier sistema con API puede conectarse a jnfor. Si además publicas un manifiesto `jnfor.json`, tus usuarios solo pegan tu dominio en **Conexiones › Conectar app** y jnfor arma todo solo. Si agregas el intercambio de llave, ni siquiera tienen que copiarla.

## 1. Publica el manifiesto

Sirve este archivo en `https://tu-dominio.com/.well-known/jnfor.json`:

```json
{
  "jnfor": 1,
  "name": "Mi Plataforma",
  "api_base": "https://tu-dominio.com/api/v1",
  "auth": {
    "type": "bearer",
    "label": "Llave de API",
    "help": "Panel › Integraciones › Llaves de API"
  },
  "test": "/me",
  "notes": "Las fechas van en formato AAAA-MM-DD. Los montos están en MXN.",
  "operations": [
    { "method": "GET", "path": "/pedidos", "description": "Lista pedidos. Parámetros: desde, hasta, estado." },
    { "method": "GET", "path": "/pedidos/{id}", "description": "Detalle de un pedido." },
    { "method": "GET", "path": "/clientes", "description": "Lista clientes. Parámetros: buscar." },
    { "method": "PUT", "path": "/pedidos/{id}", "description": "Cambia el estado de un pedido: {\"estado\":\"enviado\"}." }
  ],
  "connect_url": "https://tu-dominio.com/integraciones/jnfor/autorizar",
  "token_url": "https://tu-dominio.com/integraciones/jnfor/token"
}
```

- `auth.type`: `none`, `bearer`, `header` (agrega `"header": "X-API-Key"`) o `basic`.
- `test`: una ruta GET sin parámetros obligatorios; jnfor la usa para comprobar la conexión.
- `operations`: describe bien cada ruta y sus parámetros. Es lo que lee el jn para saber qué pedir.
- `connect_url` y `token_url` son opcionales y activan el botón **«Conectar con Mi Plataforma»**.
- Si ya tienes un `openapi.json`, también sirve: jnfor lo detecta solo en las rutas comunes.

## 2. Intercambio de llave (opcional, recomendado)

1. El usuario pulsa **Conectar** en jnfor. jnfor lo envía a tu `connect_url` con `client=jnfor`, `callback` y `state`.
2. Tu plataforma confirma la sesión del usuario, le pregunta si autoriza a jnfor, crea una llave de API **de solo lectura** y guarda un `code` de un solo uso (válido 5 minutos) asociado a esa llave.
3. Rediriges a `callback?state=…&code=…` (o `callback?state=…&error=denegado` si no autorizó).
4. jnfor canjea el código en tu `token_url` de servidor a servidor y espera `{"api_key": "…"}`.

Ejemplo mínimo en PHP para tu plataforma:

```php
// GET /integraciones/jnfor/autorizar
$usuario = requiere_sesion();
$callback = $_GET['callback'] ?? '';
$state = $_GET['state'] ?? '';
if (!preg_match('#^https://[a-z0-9.-]+/connect/callback$#i', $callback)) exit('Callback no válido');
if ($_SERVER['REQUEST_METHOD'] === 'POST' && csrf_valido()) {
    $llave = crear_llave_api($usuario['id'], 'jnfor', 'lectura');
    $code = bin2hex(random_bytes(24));
    guardar_codigo($code, $llave, time() + 300);   // un solo uso
    header('Location: ' . $callback . '?' . http_build_query(['state' => $state, 'code' => $code]));
    exit;
}
// muestra: «jnfor quiere consultar tus datos. [Autorizar] [Cancelar]»

// POST /integraciones/jnfor/token   (llamada de servidor a servidor)
$in = json_decode(file_get_contents('php://input'), true);
$llave = canjear_codigo($in['code'] ?? '');       // null si no existe, expiró o ya se usó
header('Content-Type: application/json');
if (!$llave) { http_response_code(400); echo '{"error":"codigo_invalido"}'; exit; }
echo json_encode(['api_key' => $llave]);
```

## 3. Botón «Conectar con jnfor» en tu panel

También puedes iniciar el flujo desde tu plataforma:

```html
<a href="https://jnfor.com/connect/start?manifest=https%3A%2F%2Ftu-dominio.com%2F.well-known%2Fjnfor.json">
  Conectar con jnfor
</a>
```

## Seguridad
- jnfor guarda la llave cifrada (AES-256-GCM) y nunca la muestra al jn ni la envía a la IA.
- Las conexiones de usuarios solo pueden apuntar a direcciones públicas.
- Por defecto el jn solo hace GET; cualquier POST, PUT, PATCH o DELETE requiere que el usuario permita cambios y confirme cada acción.
