> ## Documentation Index
> Fetch the complete documentation index at: https://developers.confiopagos.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conviértete en partner

> Aprende a integrar Confío con tu plataforma paso a paso

<Warning>
  **Esta guía es SOLO para el programa de partners de Confío**. Si solo
  necesitas consumir la API pública de Confío o recibir webhooks estándar, esta
  guía NO aplica para ti. Consulta "Cuándo usar esta guía".
</Warning>

## Cuándo usar esta guía

### Integración estándar (NO requiere esta guía)

Usa la integración estándar si quieres:

* Consumir la API de Confío para crear pagos desde tu aplicación.
* Recibir webhooks de Confío sobre cambios de estado de pagos.
* Usar una cuenta centralizada de Confío para procesar pagos de todos tus usuarios.

En ese caso:

1. Contacta a tu gerente de cuenta de Confío para obtener tu `CONFIO_ACCESS_TOKEN`.
2. Proporciona la URL de tu endpoint de webhooks y el token que Confío debe usar para autenticarse contra ese endpoint.
3. Comienza con la [guía de creación de pagos](/cookbooks/create-payment) y la [guía de webhooks](/cookbooks/webhooks).

### Programa de partners (SÍ requiere esta guía)

Esta guía aplica si:

* Eres un **Partner** (por ejemplo, Shopify, Dropi, WooCommerce u otra plataforma de e-commerce).
* Cada comercio de tu plataforma conecta su propia tienda de Confío.
* Confío debe validar un token emitido por tu plataforma antes de crear la integración.
* Tu plataforma debe recibir un token emitido por Confío para llamar la API pública en nombre de esa integración.

> Confío admite distintos flujos de Partner. Esta guía documenta el contrato
> público para Partners que exponen endpoints propios (`/merchant` y
> `/notifications`). Shopify y WooCommerce tienen flujos específicos gestionados
> por la interfaz de Confío.

## Conceptos y tokens

Confío registrará una URL base de tu API (`PARTNER_BASE_URL`). A partir de esa
URL, Confío llama rutas fijas:

| Propósito                             | Ruta llamada por Confío                 |
| ------------------------------------- | --------------------------------------- |
| Validar token y obtener comercio      | `GET {PARTNER_BASE_URL}/merchant`       |
| Enviar handshake, teardown y webhooks | `POST {PARTNER_BASE_URL}/notifications` |

Por ejemplo, si tu URL base es `https://tu-api.com/confio`, Confío llamará:

* `GET https://tu-api.com/confio/merchant`
* `POST https://tu-api.com/confio/notifications`

Tokens:

* **`PARTNER_ACCESS_TOKEN`**: token que genera tu plataforma. El comercio lo copia en Confío al activar la integración. Confío lo usa como `Authorization: Bearer <PARTNER_ACCESS_TOKEN>` cuando llama a tus endpoints. Debe seguir siendo válido mientras la integración esté activa.
* **`CONFIO_ACCESS_TOKEN`**: token que Confío genera al crear la integración. Confío lo envía en el webhook de `handshake`. Tu plataforma debe guardarlo y usarlo como `Authorization: Bearer <CONFIO_ACCESS_TOKEN>` al llamar la API pública de Confío.

## Resumen del flujo

```mermaid theme={null}
sequenceDiagram
    participant Usuario as Comercio
    participant Partner as Tu plataforma
    participant Confio as Confío

    Partner->>Usuario: Genera PARTNER_ACCESS_TOKEN
    Usuario->>Confio: Activa integración con el token
    Confio->>Partner: GET {PARTNER_BASE_URL}/merchant (Bearer PARTNER_ACCESS_TOKEN)
    Partner-->>Confio: 200 { id, name }
    Confio->>Partner: POST {PARTNER_BASE_URL}/notifications (event=handshake)
    Note over Partner,Confio: Authorization: Bearer PARTNER_ACCESS_TOKEN + X-Confio-Event + X-Confio-Checksum
    Partner-->>Confio: 2xx
    Partner->>Confio: API pública con Bearer CONFIO_ACCESS_TOKEN
    Confio->>Partner: Webhooks futuros en /notifications
```

## Requisitos previos

Antes de activar integraciones, coordina con Confío:

1. Registro del Partner en Confío.
2. Configuración de la URL base de tu API (`PARTNER_BASE_URL`).
3. Los eventos de webhook soportados por este contrato:
   * `payment.statusChanged`
   * `paymentAttempt.statusChanged`

Tu plataforma debe implementar:

1. `GET {PARTNER_BASE_URL}/merchant`
2. `POST {PARTNER_BASE_URL}/notifications`
3. Generación y validación de `PARTNER_ACCESS_TOKEN`.
4. Almacenamiento seguro del `CONFIO_ACCESS_TOKEN` recibido en el handshake.

## Paso 1: Generar el `PARTNER_ACCESS_TOKEN`

Tu plataforma debe permitir que el comercio genere un token para conectar su cuenta con Confío. Este token:

* Debe identificar inequívocamente al comercio en tu plataforma.
* Debe poder revocarse si la integración se desactiva.
* Debe permanecer válido mientras la integración esté activa, porque Confío lo reutiliza en webhooks futuros.

Ejemplo:

```javascript theme={null}
function generatePartnerAccessToken(merchantId) {
  const token = generateSecureToken();

  storeTokenForMerchant(merchantId, token, {
    purpose: "confio_integration",
    active: true,
    createdAt: new Date(),
  });

  return token;
}
```

## Paso 2: Implementar `GET /merchant`

Confío usa este endpoint para validar el `PARTNER_ACCESS_TOKEN` y obtener la información del comercio.

### Solicitud

```bash theme={null}
curl -X GET "https://tu-api.com/confio/merchant" \
  -H "Authorization: Bearer PARTNER_ACCESS_TOKEN"
```

> Este ejemplo asume `PARTNER_BASE_URL=https://tu-api.com/confio`.

### Respuesta 200

```json theme={null}
{
  "id": "platform_merchant_12345",
  "name": "Tienda Ejemplo"
}
```

Campos:

* `id`: identificador del comercio en tu plataforma.
* `name`: nombre visible del comercio.

### Errores recomendados

* `401 Unauthorized`: falta el bearer token o el token es inválido.
* `403 Forbidden`: token revocado o no autorizado.
* `404 Not Found`: comercio no encontrado.
* `429 Too Many Requests`: rate limit.
* `5xx`: error interno o dependencia no disponible.

### Ejemplo de implementación

```javascript theme={null}
app.get("/confio/merchant", (req, res) => {
  const authHeader = req.headers.authorization;

  if (!authHeader?.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Bearer token required" });
  }

  const partnerAccessToken = authHeader.substring("Bearer ".length);
  const tokenData = verifyPartnerAccessToken(partnerAccessToken);

  if (!tokenData || tokenData.purpose !== "confio_integration") {
    return res.status(401).json({ error: "Invalid token" });
  }

  const merchant = getMerchantInfo(tokenData.merchantId);
  if (!merchant) {
    return res.status(404).json({ error: "Merchant not found" });
  }

  return res.json({
    id: merchant.id,
    name: merchant.name,
  });
});
```

## Paso 3: Recibir el webhook `handshake`

Después de validar el comercio, Confío crea un `CONFIO_ACCESS_TOKEN` y lo entrega a tu plataforma con un webhook `handshake`.

### Solicitud

```bash theme={null}
curl -X POST "https://tu-api.com/confio/notifications" \
  -H "Authorization: Bearer PARTNER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Confio-Event: handshake" \
  -H "X-Confio-Checksum: 4F6A..." \
  -d '{
    "event": "handshake",
    "data": {
      "organization": "01JYPD4F81VSTY57TWM4WKDMSW",
      "store": "01JYPD4KMSGXW0B58YYSNMGC51",
      "token": "CONFIO_ACCESS_TOKEN"
    },
    "timestamp": 1710345600,
    "signature": {
      "properties": ["organization", "store", "token"],
      "checksum": "4F6A..."
    }
  }'
```

Campos importantes:

* `data.organization`: identificador de la organización en Confío.
* `data.store`: identificador de la tienda en Confío.
* `data.token`: `CONFIO_ACCESS_TOKEN` que tu plataforma debe guardar.
* `X-Confio-Event`: también contiene el evento (`handshake`).
* `X-Confio-Checksum`: contiene el mismo valor de `signature.checksum`.

## Firma/checksum de webhooks

Confío incluye un checksum SHA-256 en cada webhook. Para validarlo:

1. Toma los valores de `data` en el orden indicado por `signature.properties`.
2. Concatena esos valores como strings.
3. Concatena `timestamp`.
4. Concatena la clave de firma.
5. Calcula SHA-256 y representa el resultado en hexadecimal **mayúscula**, sin prefijos como `sha256=`.

Para webhooks del programa de partners, la clave de firma es el `CONFIO_ACCESS_TOKEN` de la integración. En el `handshake`, esa clave es el mismo `data.token` que estás recibiendo.

Ejemplo para `handshake`:

```javascript theme={null}
import { createHash, timingSafeEqual } from "node:crypto";

function checksum(data, properties, timestamp, key) {
  const input = [
    ...properties.map((property) => String(data[property] ?? "")),
    String(timestamp),
    key,
  ].join("");

  return createHash("sha256").update(input).digest("hex").toUpperCase();
}

function safeEqual(a, b) {
  const left = Buffer.from(a);
  const right = Buffer.from(b);
  return left.length === right.length && timingSafeEqual(left, right);
}

function verifyConfioChecksum(payload, signatureKey) {
  const expected = checksum(
    payload.data,
    payload.signature.properties,
    payload.timestamp,
    signatureKey,
  );

  return safeEqual(expected, payload.signature.checksum);
}

// Handshake: el token recibido es la clave de firma.
verifyConfioChecksum(handshakePayload, handshakePayload.data.token);
```

## Ejemplo de endpoint `POST /notifications`

```javascript theme={null}
app.post("/confio/notifications", (req, res) => {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Bearer token required" });
  }

  const partnerAccessToken = authHeader.substring("Bearer ".length);
  if (!verifyPartnerAccessToken(partnerAccessToken)) {
    return res.status(401).json({ error: "Invalid partner token" });
  }

  const event = req.headers["x-confio-event"];
  if (!event || event !== req.body.event) {
    return res.status(400).json({ error: "Invalid X-Confio-Event" });
  }

  switch (event) {
    case "handshake": {
      const { organization, store, token } = req.body.data;

      if (!verifyConfioChecksum(req.body, token)) {
        return res.status(400).json({ error: "Invalid checksum" });
      }

      storeConfioAccessToken({
        organization,
        store,
        token,
        partnerAccessToken,
      });
      return res.json({ success: true });
    }

    case "teardown": {
      const { organization, store } = req.body.data;
      const confioAccessToken =
        getConfioAccessTokenForPartnerToken(partnerAccessToken);

      if (!verifyConfioChecksum(req.body, confioAccessToken)) {
        return res.status(400).json({ error: "Invalid checksum" });
      }

      removeConfioIntegration({ organization, store });
      return res.json({ success: true });
    }

    case "payment.statusChanged":
    case "paymentAttempt.statusChanged": {
      const confioAccessToken =
        getConfioAccessTokenForPartnerToken(partnerAccessToken);

      if (!verifyConfioChecksum(req.body, confioAccessToken)) {
        return res.status(400).json({ error: "Invalid checksum" });
      }

      processWebhook(req.body);
      return res.json({ success: true });
    }

    default:
      return res.status(400).json({ error: `Unsupported event: ${event}` });
  }
});
```

## Paso 4: Llamar la API pública de Confío

Usa el `CONFIO_ACCESS_TOKEN` recibido en el `handshake` para autenticar llamadas a Confío.

Ejemplo:

```bash theme={null}
curl -X GET "https://api.confiopagos.com/v1/stores/{store}/payments/{payment}" \
  -H "Authorization: Bearer CONFIO_ACCESS_TOKEN" \
  -H "Content-Type: application/json"
```

Consulta la [referencia de API](/api-reference) para los endpoints disponibles.

## Webhooks posteriores

Para Partners que usan este contrato, Confío crea automáticamente un webhook hacia:

```text theme={null}
{PARTNER_BASE_URL}/notifications
```

Los eventos enviados son:

* `payment.statusChanged`
* `paymentAttempt.statusChanged`

Confío solo envía estos webhooks a la integración que creó el pago con su `CONFIO_ACCESS_TOKEN`.

Estos webhooks usan el mismo formato de envoltura (`event`, `data`, `timestamp`, `signature`) y se autentican con:

```http theme={null}
Authorization: Bearer PARTNER_ACCESS_TOKEN
X-Confio-Event: <event>
X-Confio-Checksum: <checksum>
```

Para ejemplos de payload de pagos, consulta la [guía de webhooks](/cookbooks/webhooks).

## Eliminar integración (`teardown`)

Cuando la integración se inactiva en Confío, Confío envía un webhook `teardown` a tu endpoint.

```bash theme={null}
curl -X POST "https://tu-api.com/confio/notifications" \
  -H "Authorization: Bearer PARTNER_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Confio-Event: teardown" \
  -H "X-Confio-Checksum: 9C1B..." \
  -d '{
    "event": "teardown",
    "data": {
      "organization": "01JYPD4F81VSTY57TWM4WKDMSW",
      "store": "01JYPD4KMSGXW0B58YYSNMGC51"
    },
    "timestamp": 1710345600,
    "signature": {
      "properties": ["organization", "store"],
      "checksum": "9C1B..."
    }
  }'
```

Para validar este checksum, usa el `CONFIO_ACCESS_TOKEN` que guardaste durante el `handshake`.

## Seguridad y buenas prácticas

1. Usa HTTPS siempre.
2. Valida `Authorization: Bearer PARTNER_ACCESS_TOKEN` en cada solicitud recibida desde Confío.
3. Valida `X-Confio-Event` y `signature.checksum` antes de procesar el payload.
4. Guarda `CONFIO_ACCESS_TOKEN` de forma segura.
5. Diseña `/notifications` de forma idempotente: Confío puede reintentar webhooks si no recibe una respuesta `2xx`.
6. Registra solicitudes y respuestas para auditoría y soporte.

## Pruebas de integración

Flujo recomendado:

1. Genera un `PARTNER_ACCESS_TOKEN` en tu entorno de pruebas.
2. Activa la integración en el sandbox de Confío.
3. Verifica que Confío llama `GET {PARTNER_BASE_URL}/merchant`.
4. Verifica que recibes el webhook `handshake` y guardas el `CONFIO_ACCESS_TOKEN`.
5. Crea un pago usando la API pública con `CONFIO_ACCESS_TOKEN`.
6. Confirma que recibes webhooks de estado en `{PARTNER_BASE_URL}/notifications`.

## Soporte y recursos adicionales

* [Guía de creación de pagos](/cookbooks/create-payment)
* [Guía de webhooks](/cookbooks/webhooks)
* [Referencia de API](/api-reference)
* [soporte@confiopagos.com](mailto:soporte@confiopagos.com)
