[KOIN SDK] Payment Method Selector

HTML

<!-- SDK de Koin -->
<script src="https://portal-dev.koin.com.br/checkout/sdk/v1/methods.js"></script>
<!-- SDK de Koin -->

<!-- ========== HTML ========== -->
<div class="app">
  <h2>Koin Payment Method Selector – Playground</h2>
  <h5>Pegá un transaction_id de una transacción de selección de medio de pago.</h5>

  <label for="transactionId">Transaction ID</label>
  <input
    type="text"
    id="transactionId"
    placeholder="Ej: 0636dba0-5284-4fc4-8ae2-0a50d17a82a5"
  />

  <button type="button" id="start-btn">Initialize experience</button>

  <div id="checkout-container"></div>

  <h3>Logs</h3>
  <div id="log-container"></div>
</div>

CSS

body {
    font-family: Arial, sans-serif;
    background: #f5f5f5;
  }

  .app {
    max-width: 520px;
    margin: 40px auto;
    padding: 20px;
    background: #ffffff;
    border-radius: 8px;
  }

  label {
    display: block;
    margin-bottom: 6px;
    font-weight: bold;
  }

  input {
    width: 100%;
    padding: 8px;
    margin-bottom: 12px;
    box-sizing: border-box;
  }

  button {
    width: 100%;
    padding: 10px;
    background: #000;
    color: #fff;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }

  button:hover {
    opacity: 0.9;
  }

  #checkout-container {
    margin-top: 20px;
  }

  #log-container {
    margin-top: 12px;
    padding: 10px;
    background: #111;
    color: #eee;
    font-family: monospace;
    font-size: 12px;
    border-radius: 6px;
    max-height: 220px;
    overflow-y: auto;
  }

  .log {
    margin-bottom: 6px;
  }

  .log.info {
    color: #9cdcfe;
  }

  .log.event {
    color: #4ec9b0;
  }

  .log.error {
    color: #f44747;
  }

  .log.warn {
    color: #dcdcaa;
  }

JavaScript

function log(message, type = "info") {
    const container = document.getElementById("log-container");
    const div = document.createElement("div");
    const time = new Date().toLocaleTimeString();

    div.className = `log ${type}`;
    div.textContent = `[${time}] ${message}`;
    container.appendChild(div);
    container.scrollTop = container.scrollHeight;
  }

  async function onClickStart() {
    const transactionId = document.getElementById("transactionId").value.trim();

    if (!transactionId) {
      log("Transaction ID vacío", "warn");
      alert("Por favor ingresá un Transaction ID");
      return;
    }

    if (!window.KoinPayments) {
      log("KoinPayments no está disponible", "error");
      return;
    }

    log(`Iniciando selector para transactionId=${transactionId}`);

    try {
      const pms = await window.KoinPayments.transaction(transactionId);

      pms.onError((error) => {
        log(
          `ERROR → code=${error.code} | message=${error.message} | origin=${error.origin}`,
          "error",
        );
      });

      pms.onEvent((event, payload) => {
        log(`EVENTO → ${event}${payload ? ` | ${JSON.stringify(payload)}` : ""}`, "event");

        switch (event) {
          case "CHECKOUT_LOADED":
            log("La lista de medios cargó y el selector está listo");
            break;
          case "EXPIRED":
            log("La sesión de selección expiró", "warn");
            break;
        }
      });

      pms.onFinish((data) => {
        log(`FINISH → status=${data.status}`, "event");

        switch (data.status) {
          case "Collected":
          case "Authorized":
            log("El pago fue exitoso");
            break;
          case "Cancelled":
            log("El pago fue cancelado o expiró", "warn");
            break;
          case "Failed":
            log("Error interno irrecuperable", "error");
            break;
          case...