Skip to content

Stars

@vibegram/stars menyediakan helper production untuk pembayaran Telegram Stars: invoice builder, approval/decline pre-checkout, validasi successful payment, refund, workflow gift/business, dan fixture paid update untuk test.

Gunakan saat bot menjual digital goods, paid media, akses premium, gift, atau fitur Mini App melalui Telegram Stars.

Mapping Resmi Telegram

Plugin ini membungkus behavior Telegram Bot API tanpa mengubahnya.

Invoice Stars adalah invoice Telegram biasa dengan currency: "XTR", provider_token kosong, dan tepat satu item prices. Plugin memvalidasi aturan ini sebelum request masuk ke Telegram.

Update pre-checkout datang sebagai Update.pre_checkout_query dan harus dijawab dengan answerPreCheckoutQuery. Pembayaran selesai datang sebagai message.successful_payment. Refund dilakukan lewat refundStarPayment. Pembelian paid media datang sebagai purchased_paid_media.

Referensi: Payments, sendInvoice, createInvoiceLink, answerPreCheckoutQuery, PreCheckoutQuery, SuccessfulPayment, refundStarPayment, sendPaidMedia, dan BusinessConnection.

Install

Saat package plugin resmi ini sudah dipublish, install dari npm:

bash
npm install vibegram @vibegram/stars

Untuk saat ini, gunakan package repository sebagai local file dependency:

json
{
  "dependencies": {
    "vibegram": "^2.1.0",
    "@vibegram/stars": "file:../vibegram/plugins/stars"
  }
}

Setup

typescript
import { Bot } from 'vibegram';
import { stars } from '@vibegram/stars';

const bot = new Bot(process.env.TELEGRAM_BOT_TOKEN!);

bot.use(stars());

Middleware menambahkan helper request-scoped ctx.stars dan memulihkan nilai sebelumnya setelah handler selesai.

Invoice Stars

typescript
bot.command('beli', ctx => {
    return ctx.stars.invoice({
        title: 'Akses Premium',
        description: 'Akses premium 30 hari',
        payload: `premium:${ctx.from?.id}`,
        amount: 100,
        label: 'Premium',
    });
});

ctx.stars.invoice() mengirim sendInvoice ke chat saat ini dengan payload ini:

typescript
{
    provider_token: '',
    currency: 'XTR',
    prices: [{ label: 'Premium', amount: 100 }]
}

Untuk subscription, gunakan periode 30 hari yang didukung Telegram:

typescript
await ctx.stars.invoice({
    title: 'Premium subscription',
    description: 'Akses premium recurring 30 hari',
    payload: `sub:${ctx.from?.id}`,
    amount: 500,
    subscriptionPeriod: 2592000,
});
typescript
const link = await ctx.stars.createInvoiceLink({
    title: 'Akses Premium',
    description: 'Akses premium 30 hari',
    payload: 'premium:42',
    amount: 100,
});

Simpan payload di tabel order sebelum link dikirim.

Guard Pre-Checkout

typescript
bot.on('pre_checkout_query', async ctx => {
    try {
        await ctx.stars.approvePreCheckout({
            payloadPrefix: 'premium:',
            totalAmount: 100,
        });
    } catch {
        await ctx.stars.declinePreCheckout('Order ini sudah tidak tersedia.');
    }
});

Validasi:

  • currency adalah XTR
  • total_amount cocok dengan order di server
  • invoice_payload ada di database
  • order masih tersedia dan belum fulfilled

Telegram mengharapkan jawaban pre-checkout cepat. Jaga handler ini tetap ringan.

Pembayaran Berhasil

typescript
bot.on('message:successful_payment', async ctx => {
    const payment = ctx.stars.requireSuccessfulPayment({
        payloadPrefix: 'premium:',
    });

    await activatePremium({
        payload: payment.invoice_payload,
        chargeId: payment.telegram_payment_charge_id,
        amount: payment.total_amount,
    });

    await ctx.reply('Premium aktif.');
});

Lakukan fulfillment hanya setelah successful_payment, bukan setelah invoice dikirim atau pre-checkout disetujui.

Refund

typescript
await ctx.stars.refund(ctx.from!.id, 'telegram-payment-charge-id');

Saat sedang menangani update successful-payment:

typescript
await ctx.stars.refundSuccessfulPayment();

Catat status refund di database agar command yang sama tidak mencoba refund berulang kali.

typescript
await ctx.stars.paidMedia({
    starCount: 25,
    payload: `gallery:${ctx.from?.id}`,
    media: [
        { type: 'photo', media: 'https://example.com/photo.jpg' },
    ],
    caption: 'Galeri premium',
});

Fixture purchase paid media untuk test:

typescript
import { createPaidMediaPurchasedUpdate } from '@vibegram/stars';

const update = createPaidMediaPurchasedUpdate({
    userId: 42,
    paidMediaPayload: 'gallery:42',
});

Gift Dan Business Workflow

typescript
await ctx.stars.gifts.send(ctx.from!.id, 'gift-id', {
    text: 'Terima kasih sudah mendukung kami',
});

await ctx.stars.gifts.premium(ctx.from!.id, 3, 1000, {
    text: 'Hadiah Premium',
});

Helper business account:

typescript
await ctx.stars.business.getStarBalance('business-connection-id');
await ctx.stars.business.transferStars('business-connection-id', 250);
await ctx.stars.business.convertGiftToStars('business-connection-id', 'owned-gift-id');
await ctx.stars.business.upgradeGift('business-connection-id', 'owned-gift-id', {
    star_count: 0,
});
await ctx.stars.business.transferGift('business-connection-id', 'owned-gift-id', 123456789);

Method ini membutuhkan business bot rights Telegram yang sesuai.

Fixture Test

typescript
import {
    createPreCheckoutQueryUpdate,
    createSuccessfulPaymentUpdate,
} from '@vibegram/stars';

const preCheckout = createPreCheckoutQueryUpdate({
    payload: 'premium:42',
    totalAmount: 100,
});

const successful = createSuccessfulPaymentUpdate({
    payload: 'premium:42',
    totalAmount: 100,
    telegramPaymentChargeId: 'charge-1',
});

Options Dan API

Export utama: stars(), buildStarsInvoice(), createPreCheckoutQueryUpdate(), createSuccessfulPaymentUpdate(), createPaidMediaPurchasedUpdate(), StarsPluginError, StarsFlavor, dan type TypeScript terkait.

buildStarsInvoice(options) menerima:

OptionTypeDeskripsi
titlestringNama produk, maksimal 32 karakter
descriptionstringDeskripsi produk, maksimal 255 karakter; default ke title
payloadstringPayload order server-side, maksimal 128 bytes
amountnumberJumlah Stars saat memakai satu price otomatis
labelstringLabel harga, default Stars
pricesLabeledPrice[]Price list eksplisit; Stars wajib tepat satu item
subscriptionPeriod2592000Periode subscription 30 hari opsional
extraobjectField invoice Telegram tambahan

Keamanan Dan Rekonsiliasi

  • Buat invoice di server.
  • Perlakukan payload sebagai order ID opaque, bukan state user yang dipercaya.
  • Persist order sebelum invoice dikirim.
  • Validasi pre-checkout dari database.
  • Fulfill hanya setelah successful_payment.
  • Buat fulfillment idempotent.
  • Simpan telegram_payment_charge_id dan status refund.
  • Gunakan @vibegram/throttler untuk offer berbayar skala broadcast dan jangan retry sendInvoice secara buta.

Validasi

Plugin ini punya test untuk payload invoice Stars, handling pre-checkout, validasi successful payment, helper refund, helper gift/business, dan fixture paid media.

bash
npm run plugins:validate
npm run docs:build

Released under the ISC License.