answerPreCheckoutQuery
Returns: TrueOfficial docs ↗
Once the user has confirmed their payment and shipping details, the Bot API sends the final confirmation in the form of an Update with the field pre_checkout_query. Use this method to respond to such pre-checkout queries. On success, True is returned. Note: The Bot API must receive an answer within 10 seconds after the pre-checkout query was sent.
Parameters
pre_checkout_query_idStringRequiredUnique identifier for the query to be answered
okBooleanRequiredSpecify True if everything is alright (goods are available, etc.) and the bot is ready to proceed with the order. Use False if there are any problems.
error_messageStringOptionalRequired if ok is False. Error message in human readable form that explains the reason for failure to proceed with the checkout (e.g. "Sorry, somebody just bought the last of our amazing black T-shirts while you were busy filling out your payment details. Please choose a different color or garment!"). Telegram will display this message to the user.
Returns
On success, True is returned.
GramIO Usage
typescript
import { Bot } from "gramio";
const bot = new Bot(process.env.BOT_TOKEN as string);
// Handle pre_checkout_query — confirm the order is still valid
bot.preCheckoutQuery(async (ctx) => {
const query = ctx.preCheckoutQuery;
// Check stock / inventory before approving
const available = await checkInventory(
query.invoice_payload,
query.total_amount,
query.currency
);
if (available) {
// Approve — payment will proceed
await ctx.answerPreCheckoutQuery({ ok: true });
} else {
// Reject — payment is cancelled with this message shown to the user
await ctx.answerPreCheckoutQuery({
ok: false,
error_message:
"Sorry, this item is no longer available. Please try a different option.",
});
}
});
// Direct API call
await bot.api.answerPreCheckoutQuery({
pre_checkout_query_id: "query_id_here",
ok: true,
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: query is too old and response timeout expired or query id is invalid | Did not answer within 10 seconds — call this immediately, before any async inventory checks |
| 400 | Bad Request: error_message is required when ok is False | ok: false sent without an error_message — always provide a user-facing reason for rejection |
| 429 | Too Many Requests: retry after N | Rate limit hit — check retry_after, use auto-retry plugin |
TIP
Use GramIO's auto-retry plugin to handle 429 errors automatically.
Tips & Gotchas
- Answer within 10 seconds — this is a hard deadline. The pre-checkout query expires after 10 seconds. Start your validation immediately. If your inventory check might be slow, consider pre-caching availability or running checks before the payment step.
- Answering
ok: trueimmediately triggers the charge. After your bot sendsok: true, Telegram charges the user's payment method. There is no additional confirmation step — make sure your validation is complete before approving. error_messageis shown directly to the user whenok: false. Write a clear, friendly, human-readable message explaining why the order can't proceed. Avoid technical jargon.- Always handle
successful_paymentupdates too. Afterok: true, Telegram sends asuccessful_paymentmessage to the chat. Use this to fulfill the order, generate receipts, and update your database. Never rely solely on the pre-checkout step to record orders. invoice_payloadis your order reference. The payload you set insendInvoicecomes back in the pre-checkout query. Use it to identify which order is being confirmed (e.g., order ID, product SKU, user-specific data).- Race conditions are possible. Multiple users can initiate checkout for the same item simultaneously. Check and reserve stock atomically in your backend before approving.
See Also
sendInvoice— Send the payment invoice that triggers this flowanswerShippingQuery— Handle shipping address validation (sent before pre-checkout)PreCheckoutQuery— The update object with full order details