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 negocioEn Billete
Una publicación de un productoUn enlace de pago de producto
"La M negra, 2 unidades" por mensajeLa misma URL con parámetros
Una membresía o un club mensualUn enlace de plan
Lo que preguntas por mensaje (tu usuario, la talla)collect y customFields del enlace
Una ventaUn 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 physical y 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_…
  • adjustableQuantity deja que el cliente elija cuántas compra; maxQuantity limita cada compra, y nunca pasa de las existencias. Sin él, cada compra es de una unidad.
  • variants limita el enlace a algunas variantes del producto; sin él, ofrece todas las activas.
  • collect pide nombre, teléfono o dirección (el correo se pide siempre). customFields agrega hasta 5 preguntas propias de tipo text, number o select.
  • afterCompletion muestra un mensaje al pagar o, con { type: "redirect", url }, lleva a tu página; ahí {CHECKOUT_ID} se reemplaza por el ID del checkout.
  • submitLabel cambia el texto del botón: pay (Pagar), subscribe (Suscribirme), book (Reservar) o donate (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=VERANO

quantity 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); // definitivo

Un 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.

EventoQué pasóQué hace tu aplicación
checkout.completedAlguien pagó por un enlace (paymentLinkId).Registra la venta y escríbele para coordinar.
payment_link.deletedSe eliminó el enlace, o el producto o plan que vendía.Quítalo de donde lo publicaste.

Referencia de enlaces de pago · Reglas de enlaces de pago