Artículos sobre: Enlaces de pago
Este artículo también está disponible en:

Conectar Pagos de Fygaro con Wix


Descargo de responsabilidad


Asegúrate de hacer una copia de seguridad de tu sitio antes de implementar esta integración y de probarla completamente antes de habilitarla en producción.


Conectar Fygaro con Wix para recibir pagos requiere:


  • Un plan de suscripción de Fygaro con capacidades de Hooks.

  • Una cuenta de Wix con una tienda en línea o función de comercio electrónico.


¿Buscas una mejor solución? Explora Fygaro Shops – el constructor de tiendas web listo para usar, sin necesidad de código, con pagos y logística integrados para simplificar tu negocio.Ultima actualización: 14 Enero 2026 (Incluye devoluciones y mejoras de seguridad)


Paso 1: Accede al Editor de Sitio de Wix


  1. Inicia sesión en tu panel de control de Wix.

  1. Abre el editor de tu sitio web.


Paso 2: Activa el Modo Desarrollador


  1. En la barra superior del editor del sitio, haz clic en Modo Dev.

  1. Sigue los pasos de activación para habilitar el Modo Desarrollador.


Paso 3: Instala el Paquete NPM Requerido


  1. Una vez que el Modo Desarrollador esté habilitado, haz clic en Paquetes y Aplicaciones en la barra de menú izquierda.

  1. Haz clic en el signo + junto a npm e instala el paquete jsonwebtoken.


Paso 4: Crea los Archivos Backend


  1. En la barra de menú izquierda, selecciona Backend y Público.

  1. Haz clic en el signo + bajo Backend, luego haz clic en Agregar Archivo .js.

  1. Nombra el archivo fygaro.web.js e incluye el siguiente código:


// Working ample Code Block, update as needed.

import { Permissions, webMethod } from "wix-web-module";
import jwt from 'jsonwebtoken'; // Install "jsonwebtoken" package in Wix Velo settings
import crypto from "crypto";
import { fetch } from "wix-fetch";
import wixSecretsBackend from "wix-secrets-backend";


export const getFJWT = webMethod(
Permissions.Anyone,
async (api_public, api_secrete, cartTotal, taxes, currency, orderNumber) => {

const SECRET_KEY = api_secrete;
const KID = api_public;


var payload = {
amount: cartTotal,
tax: taxes,
currency: currency,
custom_reference: orderNumber,
};

if(taxes == 0){
payload = {
amount: cartTotal,
currency: currency,
custom_reference: orderNumber,
};
}

const options = {
header: { kid: KID },
algorithm: 'HS256',
};


return jwt.sign(payload, SECRET_KEY, options);

}
);

/* -----------------------------
Refund API (external payment)
-------------------------------- */

const FYGARO_BASE = "https://api.fygaro.com/api/v1/external/payment";

function to2dp(amount) {
// expects number like 12.3 -> "12.30"
return Number(amount).toFixed(2);
}

//refund function
export async function fygaroRefund({
apiKeyKid, // Fygaro API key (UUID string) -> JWT header kid
apiSecret, // Fygaro shared secret -> HS256 signing key
transactionId, // original Fygaro tx id (UUID)
amount, // optional: number (major units). If undefined => full refund
}) {
const iat = Math.floor(Date.now() / 1000);
const exp = iat + 300; // 5 minutes

const payload = {
transactionId,
iat,
exp,
...(amount !== undefined ? { amount: to2dp(amount) } : {}),
};

const token = jwt.sign(payload, apiSecret, {
algorithm: "HS256",
header: { kid: apiKeyKid, typ: "JWT" },
});

const res = await fetch(`${FYGARO_BASE}/refund/`, {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ token }),
});

const text = await res.text();
let data;
try { data = JSON.parse(text); } catch { data = { raw: text }; }

if (!res.ok) {
// Bubble up something useful for Wix logs
throw new Error(`Fygaro refund failed (${res.status}): ${JSON.stringify(data)}`);
}

// Expected 200: { transactionId, amount } :contentReference[oaicite:7]{index=7}
return data;
}


/* -----------------------------
Secrets Manager helpers
-------------------------------- */

function hookSecretName(keyId) {
return `fygaro_hook_secret_${keyId}`;
}

export async function getFygaroHookSecret(keyId) {
// returns the secret value by name
return wixSecretsBackend.getSecret(hookSecretName(keyId));
}

export async function upsertFygaroHookSecret(keyId, secretValue) {
const name = hookSecretName(keyId);

// listSecretInfo() returns array of { id, name, description? }
const infos = await wixSecretsBackend.listSecretInfo();
const existing = (infos || []).find((s) => s.name === name);

if (existing?.id) {
// updateSecret(secretId, { value })
await wixSecretsBackend.updateSecret(existing.id, { value: secretValue });
return { action: "updated", name };
}

// createSecret({ name, value })
await wixSecretsBackend.createSecret({ name, value: secretValue });
return { action: "created", name };
}


/* -----------------------------
Webhook signature helpers
-------------------------------- */

export function normalizeHeaders(h = {}) {
const out = {};
Object.keys(h).forEach((k) => (out[String(k).toLowerCase()] = h[k]));
return out;
}

export function parseFygaroSignature(sigHeader = "") {
const parts = String(sigHeader).split(",").map((p) => p.trim());
let t = null;
const v1 = [];
for (const part of parts) {
const idx = part.indexOf("=");
if (idx === -1) continue;
const k = part.slice(0, idx).trim();
const v = part.slice(idx + 1).trim();
if (k === "t") t = v;
if (k === "v1") v1.push(v);
}
return { t, v1 };
}

export function constantTimeEqualHex(aHex, bHex) {
if (typeof aHex !== "string" || typeof bHex !== "string") return false;
if (aHex.length !== bHex.length) return false;
let diff = 0;
for (let i = 0; i < aHex.length; i++) diff |= aHex.charCodeAt(i) ^ bHex.charCodeAt(i);
return diff === 0;
}

export function computeFygaroExpectedSignature({ secret, t, rawBody }) {
const message = `${t}.${rawBody}`;
return crypto.createHmac("sha256", secret).update(message, "utf8").digest("hex");
}


  1. Haz clic nuevamente en el signo +, pero esta vez selecciona Exponer API del Sitio.

  1. Incluye el siguiente código en el nuevo archivo:


// Working sample Code Block, update as needed
import { ok, badRequest, unauthorized, serverError } from 'wix-http-functions';
import crypto from "crypto";
import wixPaymentProviderBackend from "wix-payment-provider-backend";
import { getSecret } from "wix-secrets-backend";

function normalizeHeaders(h = {}) {
const out = {};
Object.keys(h).forEach((k) => (out[String(k).toLowerCase()] = h[k]));
return out;
}

function parseFygaroSignature(sigHeader = "") {

const parts = String(sigHeader).split(",").map((p) => p.trim());
let t = null;
const v1 = [];
for (const part of parts) {
const idx = part.indexOf("=");
if (idx === -1) continue;
const k = part.slice(0, idx).trim();
const v = part.slice(idx + 1).trim();
if (k === "t") t = v;
if (k === "v1") v1.push(v);
}
return { t, v1 };
}

// Constant-time compare for hex strings (no timingSafeEqual dependency)
function constantTimeEqualHex(aHex, bHex) {
if (typeof aHex !== "string" || typeof bHex !== "string") return false;
if (aHex.length !== bHex.length) return false;
let diff = 0;
for (let i = 0; i < aHex.length; i++) {
diff |= aHex.charCodeAt(i) ^ bHex.charCodeAt(i);
}
return diff === 0;
}



//Hook URL> https://www.mysite.com/_functions/updateTransaction
// or https://user.wix.com/_functions/updateTransaction

export async function post_updateTransaction(request) {

try {
const headers = normalizeHeaders(request.headers);

// ✅ RAW BODY (must be exact bytes)
const buf = await request.body.buffer();
const rawBody = buf.toString("utf8");

const sigHeader = headers["fygaro-signature"];
const keyId = headers["fygaro-key-id"];

if (!sigHeader || !keyId) {
console.log("Missing headers:", { hasSig: !!sigHeader, hasKeyId: !!keyId });
return badRequest({ body: { error: "Missing Fygaro-Signature or Fygaro-Key-ID" } });
}

// 🔐 Secrets Manager: create secrets like "fygaro_hook_secret_<keyId>"
const secretName = `fygaro_hook_secret_${keyId}`;
const secret = await getSecret(secretName);

if (!secret) {
console.log("Unknown keyId (no secret found):", { keyId, secretName });
return unauthorized({ body: { error: "Unknown Fygaro-Key-ID (no matching secret configured)" } });
}

const { t, v1 } = parseFygaroSignature(sigHeader);
if (!t || !v1.length) {
console.log("Malformed signature header:", { sigHeaderPreview: sigHeader.slice(0, 40) });
return badRequest({ body: { error: "Malformed Fygaro-Signature header" } });
}

// Replay window (recommended by Fygaro)
const now = Math.floor(Date.now() / 1000);
const ts = parseInt(t, 10);
if (!Number.isFinite(ts) || Math.abs(now - ts) > 300) {
console.log("Stale timestamp:", { ts, now, driftSec: Math.abs(now - ts) });
return unauthorized({ body: { error: "Stale timestamp" } });
}

// Compute HMAC as per Fygaro doc: message = t + "." + raw_body
const message = `${t}.${rawBody}`;
const expected = crypto.createHmac("sha256", secret).update(message, "utf8").digest("hex");

const valid = v1.some((sig) => constantTimeEqualHex(expected, sig));
if (!valid) {
console.log("Invalid signature:", {
keyId,
t,
v1Count: v1.length,
bodyLen: rawBody.length,
});
return unauthorized({ body: { error: "Invalid signature" } });
}

// ✅ Verified — now parse JSON
const payload = JSON.parse(rawBody);
console.log("Verified Fygaro payload keys:", Object.keys(payload || {}));

// New payload contains transactionId + customReference :contentReference[oaicite:1]{index=1}
if (!payload?.customReference || !payload?.transactionId) {
return badRequest({ body: { error: "Missing customReference or transactionId in payload" } });
}

await wixPaymentProviderBackend.submitEvent({
event: {
transaction: {
wixTransactionId: payload.customReference,
pluginTransactionId: payload.transactionId,
},
},
});

return ok({ body: { status: "ok" } });
} catch (err) {
console.error("Webhook processing failed:", err?.stack || err);
return serverError({ body: { error: String(err?.message || err) } });
}

}


Paso 5: Configura el Plugin de Pago


  1. Ve a la sección de Plugins de Servicio.

  1. Haz clic en el signo + y selecciona la opción Pagos.

  1. Cuando se te solicite un nombre, ingresa FGW (todo en mayúsculas).


Paso 6: Edita los Archivos de Configuración de FGW


  1. Ubica los archivos creados y abre FGW-config.js.

  1. Copia y pega el siguiente código en el archivo:


// Working sample Code Block, update as needed
import * as paymentProvider from 'interfaces-psp-v1-payment-service-provider';

/** @returns {import('interfaces-psp-v1-payment-service-provider').PaymentServiceProviderConfig} */
export function getConfig() {
//throw new Error('getConfig was not implemented');
return {
title: 'Fygaro Payments',
paymentMethods: [{
hostedPage: {
title: 'Fygaro Payments',
logos: {
white: {
svg: 'https://static-app.fygaro.com/static/img/10542c9bde49a22d7779.svg'
//png: 'https://freesvg.org/img/15930333081593032446pitr_Bananas_icon.png'
},
colored: {
svg: 'https://static-app.fygaro.com/static/img/10542c9bde49a22d7779.svg'
//png: 'https://freesvg.org/img/15930333081593032446pitr_Bananas_icon.png'
}
}
}
}],
credentialsFields: [{
simpleField: {
name: 'clientId',
label: 'API id'
}
},
{
simpleField: {
name: 'clientSecret',
label: 'API secret'
}
},
{
simpleField: {
name: 'clientURL',
label: 'Botton URL'
}
},
{
dropdownField: {
name: 'taxFlag',
label: 'Send Tax Detail',
options: [
{
key: '0',
value: 'No'
},
{
key: '1',
value: 'Yes'
}
]
}
}
]
}
}


  1. Abre el archivo FGW.js y pega el siguiente código:


// Working sample Code Block, update as needed
import * as paymentProvider from 'interfaces-psp-v1-payment-service-provider';
import { getFJWT, fygaroRefund, upsertFygaroHookSecret, createNewSecret } from 'backend/fygaro.web';

/**
* This payment plugin endpoint is triggered when a merchant provides required data to connect their PSP account to a Wix site.
* The plugin has to verify merchant's credentials, and ensure the merchant has an operational PSP account.
* @param {import('interfaces-psp-v1-payment-service-provider').ConnectAccountOptions} options
* @param {import('interfaces-psp-v1-payment-service-provider').Context} context
* @returns {Promise<import('interfaces-psp-v1-payment-service-provider').ConnectAccountResponse | import('interfaces-psp-v1-payment-service-provider').BusinessError>}
*/
export const connectAccount = async (options, context) => {
const { credentials } = options;

const keyId = credentials?.clientId;
const secret = credentials?.clientSecret;

if (keyId && secret) {
try {
await upsertFygaroHookSecret(keyId, secret);
} catch (e) {
console.log("Fygaro secret upsert failed:", e?.message || e);
}
}

return { credentials };


};

/**
* This payment plugin endpoint is triggered when a buyer pays on a Wix site.
* The plugin has to process this payment request but prevent double payments for the same `wixTransactionId`.
* @param {import('interfaces-psp-v1-payment-service-provider').CreateTransactionOptions} options
* @param {import('interfaces-psp-v1-payment-service-provider').Context} context
* @returns {Promise<import('interfaces-psp-v1-payment-service-provider').CreateTransactionResponse | import('interfaces-psp-v1-payment-service-provider').BusinessError>}
*/
export const createTransaction = async (options, context) => {

const {merchantCredentials, order, wixTransactionId} = options;

const api_public = merchantCredentials.clientId;
const api_secrete = merchantCredentials.clientSecret;
const redirect_url = merchantCredentials.clientURL;

const taxFlag = merchantCredentials.taxFlag;
//Check for taxes
var taxes = 0;
if(taxFlag == 1){
if(order.description.charges.tax !== undefined && order.description.charges.tax > 0){
taxes = parseInt(order.description.charges.tax) / Math.pow(10,2);
}
}

var totalAmount = parseInt(order.description.totalAmount) / Math.pow(10,2);
const currency = order.description.currency;
const orderNumber = wixTransactionId;

const fygaroCheckout = await getFJWT(api_public, api_secrete, totalAmount, taxes, currency, orderNumber);

return {

"pluginTransactionId": orderNumber,
"redirectUrl": `${redirect_url}?jwt=${fygaroCheckout}`

}

};

/**
* This payment plugin endpoint is triggered when a merchant refunds a payment made on a Wix site.
* The plugin has to process this refund request but prevent double refunds for the same `wixRefundId`.
* @param {import('interfaces-psp-v1-payment-service-provider').RefundTransactionOptions} options
* @param {import('interfaces-psp-v1-payment-service-provider').Context} context
* @returns {Promise<import('interfaces-psp-v1-payment-service-provider').CreateRefundResponse | import('interfaces-psp-v1-payment-service-provider').BusinessError>}
*/
function minorToMajor(minor) {
// Wix often provides amounts as minor units (e.g. cents).
// If you already get major units, remove this conversion.
return Number(minor) / 100;
}

export const refundTransaction = async (options, context) => {

const { merchantCredentials, pluginTransactionId, refund, wixRefundId } = options;

const api_public = merchantCredentials.clientId; // kid
const api_secrete = merchantCredentials.clientSecret; // HS256 secret

// 1) This should be the original Fygaro transactionId you saved as pluginTransactionId
const fygaroTransactionId = pluginTransactionId;

// 2) Refund amount
// If Wix provides minor units, convert. If it provides major, pass directly.
// If you want "full refund" behavior, pass undefined when refund amount is not specified.
const refundAmountMajor =
refund?.amount !== undefined ? minorToMajor(refund.amount) : undefined;

// 3) Call Fygaro refund API
const result = await fygaroRefund({
apiKeyKid: api_public,
apiSecret: api_secrete,
transactionId: fygaroTransactionId,
amount: refundAmountMajor,
});

// 4) Return back to Wix (shape may vary slightly depending on your PSP interface version)
return {
pluginRefundId: result.transactionId, // refund transaction id from Fygaro
};

};


  1. Haz clic en el botón Publicar en la esquina superior derecha del editor.


Paso 7: Conecta los Pagos de Fygaro


  1. Regresa al Panel de Control de Wix.

  1. Ve a Configuraciones y localiza la opción Aceptar Pagos.

  1. Recorre las opciones de pago hasta encontrar Fygaro y haz clic en Conectar.

  1. Ingresa tu API Key y API Secret obtenidos desde Fygaro (consulta este tutorial para saber cómo obtener tus credenciales).

  1. En el campo URL del Botón, pega el enlace del botón de pago de Fygaro (consulta este tutorial para saber cómo crear un botón de pago con monto variable).

  1. Haz clic en Conectar.


Paso 8: Configura Tu Botón de Pago en Fygaro


Cuando crees tu botón de pago en Fygaro:


  1. Activa la opción JWT en Configuraciones Avanzadas.

  1. En el campo Hook, ingresa la URL de tu sitio Wix seguido de /_functions/updateTransaction. Ejemplo:


https://www.misitio.com/_functions/updateTransaction


  1. Guarda tu botón de pago.


Paso Final: Prueba Tu Integración


Para asegurarte de que todo está configurado correctamente:


  1. Realiza una transacción de prueba por USD $1 (o el equivalente en moneda local).

  1. Confirma que el pago se procese exitosamente.


¡Ahora estás listo para comenzar a aceptar pagos con Fygaro en tu sitio de Wix!


Este tutorial es un ejemplo guiado sobre cómo implementar pagos en tu sitio existente de Wix. Fygaro no garantiza la exactitud, funcionalidad o idoneidad del mismo para tus necesidades específicas. La implementación es bajo tu propio riesgo, y podrías necesitar contratar a un desarrollador de Wix para personalizar la configuración según los requerimientos de tu cuenta.

Actualizado el: 14/01/2026

¿Este artículo te resultó útil?

Comparte tu opinión

Cancelar

¡Gracias!