# 레시피: Telegram 봇

> 봇 명령, 역할, 비공개 그룹을 파세요. 사용자마다 자기 청구서를 받고, 서명된 웹훅이 이용권을 엽니다.

봇은 돈을 보지 않습니다. `/buy`에서 사용자에게 그 사람만의 청구서 링크를 보내고, 내 서버가 `invoice.fulfilled`를 듣고 이용권을 엽니다. 모든 유료 명령이 Perly Pay에 묻기 때문에 재시작해도 잃는 것이 없습니다. Discord도 같은 방식, 역할로.

> **참고:** 어시스턴트와 함께: 이 레시피는 Perly Pay 플러그인의 `sell-bot-access` 스킬이 내 프로젝트에서 실행합니다. 실행 가능한 예제는 플러그인 저장소의 `examples/telegram-bot`(MIT)입니다.

## 작동 방식

1. **상품과 가격** — 1회 또는 평생은 '영구', 기간제는 이용권, 구독은 청구서로 갱신되는 멤버십.
2. **채팅 사용자마다 고객** — `external_id: "tg:<user id>"`. 이메일은 구독일 때만 물으세요: 갱신 청구서가 그리로 갑니다.
3. **/buy** — `metadata`에 채팅 ID를 넣은 청구서를 버튼으로 보냅니다. 멱등성 키 덕분에 사용자당 하루 청구서 하나.
4. **이용권 열기** — `invoice.fulfilled`에서 `metadata`의 채팅 ID를 꺼내 답하세요: 메시지, 1회용 초대, 역할.
5. **유료 명령** — `entitlements.check({ customer_external_id: "tg:<id>", product })`.

**/buy**

```js
const invoice = await pay.invoices.create(
  { line_items: [{ price: PRICE }], customer: customer.id, metadata: { chat_id: String(chatId) } },
  { idempotencyKey: `buy-${userId}-${today}` },
);
await tg("sendMessage", { chat_id: chatId, text: "Pay:", reply_markup: { inline_keyboard: [[{ text: "Pay", url: invoice.url }]] } });
```

## 예제 실행

1. **설치** — `examples/telegram-bot`에서 `npm install`(Node 20.12+).
2. **키** — `.env.example`을 `.env`로 복사하고 `PERLY_PAY_SECRET_KEY`에 테스트 키(`sk_test_…`)를 넣으세요.
3. **준비** — `npm run setup`이 내 키로 상품과 가격을 만들고 `.env`용 ID를 출력합니다.
4. **실행** — README에 적힌 대로 `npm start`(또는 `npm run dev`).
5. **지갑 없이 결제** — 봇에게 `/buy`를 보내고, Pay를 열어 **Simulate payment**를 누르세요: 봇이 "Payment confirmed"라고 하고 `/secret`이 답합니다.

## 함정

- 모두에게 같은 결제 링크 하나: 누가 결제했는지 알 수 없습니다. 사용자마다 채팅 ID를 담은 청구서를.
- 사용자가 "결제했어요"를 누르면 이용권 열기. 여는 것은 웹훅이나 `entitlements.check`뿐입니다.
- 봇 메모리에 둔 이용권. 재시작하면 사라집니다. Perly Pay에 물으세요.
