Vender por redes y WhatsApp
Un enlace de pago por producto o plan para publicar en Instagram o mandar por WhatsApp, sin tienda propia.
Para un negocio que vende por Instagram, TikTok o WhatsApp y no tiene tienda en línea. Casi todo se hace desde el dashboard, en Ventas › Enlaces de pago; el SDK sirve para automatizarlo. El ejemplo es una marca de franelas que publica cada modelo y responde los mensajes con un enlace.
El modelo
| En tu negocio | En Billete |
|---|---|
| Una publicación de un producto | Un enlace de pago de producto |
| "La M negra, 2 unidades" por mensaje | La misma URL con parámetros |
| Una membresía o un club mensual | Un enlace de plan |
| Lo que preguntas por mensaje (tu usuario, la talla) | collect y customFields del enlace |
| Una venta | Un checkout completado con el paymentLinkId del enlace |
- Un enlace, muchas compras. La URL no cambia: va en la biografía, en el catálogo de WhatsApp o en cada respuesta. Cada persona que lo abre recibe su propio checkout, válido por 24 horas.
- Los parámetros eligen, no crean. Para ofrecer una talla o una cantidad concreta no hace falta otro enlace: se agregan a la URL. No sirven para marcar quién lo abrió (cualquier otro parámetro se ignora); para cobrarle a una persona concreta, usa un Cobro.
- El producto manda. Precio, variantes y existencias salen del producto. Si es
physicaly tiene formas de entrega, el checkout pide cómo recibirlo, nombre y teléfono, y la venta sigue el flujo de tienda con productos físicos.
1. Crea el enlace
Desde el dashboard: Enlaces de pago › Crear enlace, elige el producto y lo que pides al cliente. Con el SDK:
const link = await billete.paymentLinks.create({
type: "product",
product: PRODUCTS.franelaBasica,
adjustableQuantity: true,
maxQuantity: 5,
collect: { name: true, phone: true },
customFields: [
{ key: "instagram", label: "Tu usuario de Instagram", type: "text", required: true },
],
afterCompletion: {
type: "message",
message: "¡Gracias! Te escribimos por WhatsApp para coordinar la entrega.",
},
}, { idempotencyKey: "enlace-franela-basica" });
// link.url: https://billete.run/l/plink_…adjustableQuantitydeja que el cliente elija cuántas compra;maxQuantitylimita cada compra, y nunca pasa de las existencias. Sin él, cada compra es de una unidad.variantslimita el enlace a algunas variantes del producto; sin él, ofrece todas las activas.collectpide nombre, teléfono o dirección (el correo se pide siempre).customFieldsagrega hasta 5 preguntas propias de tipotext,numberoselect.afterCompletionmuestra un mensaje al pagar o, con{ type: "redirect", url }, lleva a tu página; ahí{CHECKOUT_ID}se reemplaza por el ID del checkout.submitLabelcambia el texto del botón:pay(Pagar),subscribe(Suscribirme),book(Reservar) odonate(Donar).
Para una membresía, el enlace es de plan: type: "plan", plan y, si quieres limitar los ciclos que se ofrecen, months. Cada pago crea una suscripción (planes personales).
2. Comparte la opción justa
La URL acepta variant, quantity, months y coupon para abrir el checkout con algo ya elegido:
https://billete.run/l/plink_ejemplo?variant=var_m_negra&quantity=2
https://billete.run/l/plink_ejemplo?coupon=VERANOquantity solo aplica si el enlace tiene adjustableQuantity, y coupon si tu negocio acepta cupones. Si un parámetro ya no aplica (una variante eliminada, un cupón vencido), el checkout se abre como sin él. Mira parámetros en la URL.
3. Limita una preventa
maxPayments cierra el enlace al llegar a ese número de pagos; después, quien lo abre ve que ya no está disponible. Cuenta pagos, no unidades: para limitar unidades usa el stock del producto.
const preventa = await billete.paymentLinks.create({
type: "product",
product: PRODUCTS.edicionLimitada,
maxPayments: 30,
});4. Sabe quién pagó
Sin código, cada venta aparece en Pagos con el correo, los datos pedidos y las respuestas. Para avisarte o registrar la venta en tu sistema, escucha checkout.completed: el checkout trae el enlace que lo abrió (paymentLinkId), el correo (email), lo pedido con collect (customerDetails), las respuestas (customFieldValues) y lo comprado (items).
if (event.type === "checkout.completed" && event.data.paymentLinkId) {
const checkout = event.data;
await db.sales.insertIfAbsent({
checkoutId: checkout.id,
linkId: checkout.paymentLinkId,
email: checkout.email,
phone: checkout.customerDetails.phone,
instagram: checkout.customFieldValues.instagram,
});
}El metadata del enlace no pasa a sus checkouts: identifica el enlace por paymentLinkId.
5. Pausa o elimina el enlace
await billete.paymentLinks.update(link.id, { active: false }); // pausa; con true vuelve
await billete.paymentLinks.delete(link.id); // definitivoUn enlace eliminado deja de abrir checkouts y su página dice que ya no existe; los checkouts que ya abrió se pueden pagar. Eliminar un producto elimina también sus enlaces.
| Evento | Qué pasó | Qué hace tu aplicación |
|---|---|---|
checkout.completed | Alguien pagó por un enlace (paymentLinkId). | Registra la venta y escríbele para coordinar. |
payment_link.deleted | Se eliminó el enlace, o el producto o plan que vendía. | Quítalo de donde lo publicaste. |