Skip to content

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_idStringRequired
Unique identifier for the query to be answered
okBooleanRequired
Specify 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_messageStringOptional
Required 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

CodeErrorCause
400Bad Request: query is too old and response timeout expired or query id is invalidDid not answer within 10 seconds — call this immediately, before any async inventory checks
400Bad Request: error_message is required when ok is Falseok: false sent without an error_message — always provide a user-facing reason for rejection
429Too Many Requests: retry after NRate 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: true immediately triggers the charge. After your bot sends ok: true, Telegram charges the user's payment method. There is no additional confirmation step — make sure your validation is complete before approving.
  • error_message is shown directly to the user when ok: false. Write a clear, friendly, human-readable message explaining why the order can't proceed. Avoid technical jargon.
  • Always handle successful_payment updates too. After ok: true, Telegram sends a successful_payment message 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_payload is your order reference. The payload you set in sendInvoice comes 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