1#!/usr/bin/env python
2# pylint: disable=unused-argument
3# This program is dedicated to the public domain under the CC0 license.
4
5"""Basic example for a bot that can receive payment from user."""
6
7import logging
8
9from telegram import LabeledPrice, ShippingOption, Update
10from telegram.ext import (
11 Application,
12 CommandHandler,
13 ContextTypes,
14 MessageHandler,
15 PreCheckoutQueryHandler,
16 ShippingQueryHandler,
17 filters,
18)
19
20# Enable logging
21logging.basicConfig(
22 format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO
23)
24# set higher logging level for httpx to avoid all GET and POST requests being logged
25logging.getLogger("httpx").setLevel(logging.WARNING)
26
27logger = logging.getLogger(__name__)
28
29PAYMENT_PROVIDER_TOKEN = "PAYMENT_PROVIDER_TOKEN"
30
31
32async def start_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
33 """Displays info on how to use the bot."""
34 msg = (
35 "Use /shipping to get an invoice for shipping-payment, or /noshipping for an "
36 "invoice without shipping."
37 )
38
39 await update.message.reply_text(msg)
40
41
42async def start_with_shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
43 """Sends an invoice with shipping-payment."""
44 chat_id = update.message.chat_id
45 title = "Payment Example"
46 description = "Payment Example using python-telegram-bot"
47 # select a payload just for you to recognize its the donation from your bot
48 payload = "Custom-Payload"
49 # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
50 currency = "USD"
51 # price in dollars
52 price = 1
53 # price * 100 so as to include 2 decimal points
54 # check https://core.telegram.org/bots/payments#supported-currencies for more details
55 prices = [LabeledPrice("Test", price * 100)]
56
57 # optionally pass need_name=True, need_phone_number=True,
58 # need_email=True, need_shipping_address=True, is_flexible=True
59 await context.bot.send_invoice(
60 chat_id,
61 title,
62 description,
63 payload,
64 PAYMENT_PROVIDER_TOKEN,
65 currency,
66 prices,
67 need_name=True,
68 need_phone_number=True,
69 need_email=True,
70 need_shipping_address=True,
71 is_flexible=True,
72 )
73
74
75async def start_without_shipping_callback(
76 update: Update, context: ContextTypes.DEFAULT_TYPE
77) -> None:
78 """Sends an invoice without shipping-payment."""
79 chat_id = update.message.chat_id
80 title = "Payment Example"
81 description = "Payment Example using python-telegram-bot"
82 # select a payload just for you to recognize its the donation from your bot
83 payload = "Custom-Payload"
84 # In order to get a provider_token see https://core.telegram.org/bots/payments#getting-a-token
85 currency = "USD"
86 # price in dollars
87 price = 1
88 # price * 100 so as to include 2 decimal points
89 prices = [LabeledPrice("Test", price * 100)]
90
91 # optionally pass need_name=True, need_phone_number=True,
92 # need_email=True, need_shipping_address=True, is_flexible=True
93 await context.bot.send_invoice(
94 chat_id, title, description, payload, PAYMENT_PROVIDER_TOKEN, currency, prices
95 )
96
97
98async def shipping_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
99 """Answers the ShippingQuery with ShippingOptions"""
100 query = update.shipping_query
101 # check the payload, is this from your bot?
102 if query.invoice_payload != "Custom-Payload":
103 # answer False pre_checkout_query
104 await query.answer(ok=False, error_message="Something went wrong...")
105 return
106
107 # First option has a single LabeledPrice
108 options = [ShippingOption("1", "Shipping Option A", [LabeledPrice("A", 100)])]
109 # second option has an array of LabeledPrice objects
110 price_list = [LabeledPrice("B1", 150), LabeledPrice("B2", 200)]
111 options.append(ShippingOption("2", "Shipping Option B", price_list))
112 await query.answer(ok=True, shipping_options=options)
113
114
115# after (optional) shipping, it's the pre-checkout
116async def precheckout_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
117 """Answers the PreQecheckoutQuery"""
118 query = update.pre_checkout_query
119 # check the payload, is this from your bot?
120 if query.invoice_payload != "Custom-Payload":
121 # answer False pre_checkout_query
122 await query.answer(ok=False, error_message="Something went wrong...")
123 else:
124 await query.answer(ok=True)
125
126
127# finally, after contacting the payment provider...
128async def successful_payment_callback(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
129 """Confirms the successful payment."""
130 # do something after successfully receiving payment?
131 await update.message.reply_text("Thank you for your payment!")
132
133
134def main() -> None:
135 """Run the bot."""
136 # Create the Application and pass it your bot's token.
137 application = Application.builder().token("TOKEN").build()
138
139 # simple start function
140 application.add_handler(CommandHandler("start", start_callback))
141
142 # Add command handler to start the payment invoice
143 application.add_handler(CommandHandler("shipping", start_with_shipping_callback))
144 application.add_handler(CommandHandler("noshipping", start_without_shipping_callback))
145
146 # Optional handler if your product requires shipping
147 application.add_handler(ShippingQueryHandler(shipping_callback))
148
149 # Pre-checkout handler to final check
150 application.add_handler(PreCheckoutQueryHandler(precheckout_callback))
151
152 # Success! Notify your user!
153 application.add_handler(
154 MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback)
155 )
156
157 # Run the bot until the user presses Ctrl-C
158 application.run_polling(allowed_updates=Update.ALL_TYPES)
159
160
161if __name__ == "__main__":
162 main()