Skip to main content
Bot platform adapters now ship in the praisonai-bot package. praisonai bot serve still works exactly as documented here; for a standalone install see praisonai-bot Migration.
Bot pairing enables owner-approval for unknown users with inline Approve/Deny buttons sent directly to your DM.
The user messages the bot before they are allowlisted; the owner receives Approve/Deny buttons in DM.

Quick Start

1

Enable Pairing

The same config from gateway.yaml — both keys are read per-channel (PR #2856):
2

Production Environment

Without this, inline-button callbacks stop working across bot restarts.

How It Works

The pairing system intercepts messages from users not in allowed_users and routes them through an approval workflow controlled by the unknown_user_policy, publishing a pairing_approved event on the default EventBus after every successful approval (CLI, inline button, or web UI).
The pairing flow now fires only when BotConfig.is_explicitly_allowed(user_id) returns False (empty allowlist, or user not on it). Users on allowed_users skip pairing entirely — PR #2856.
Inline approvals (PR #1892): When the owner taps Approve on the Telegram / Discord / Slack DM, the requester is paired immediately on the platform type (telegram / discord / slack) so all of their later messages flow straight through. If you saw “approve looked successful but the next message was still blocked” on an older release, upgrade to pick up this fix.
Gateway mode (praisonai gateway start): As of PR #1791, the gateway polling path runs the same pairing pipeline as the standalone bot. If pairing.enabled: true is set in your gateway config, unknown users get the same Approve/Deny inline-button flow. No code changes needed — configure unknown_user_policy: "pair" and owner_user_id in your channels: YAML entry.
Behavior change in PR #1885 (Telegram only). Before this fix, Telegram bots with an empty allowed_users list ignored unknown_user_policy and let everyone through — "pair" only worked when allowed_users was non-empty. After the fix, empty allowed_users correctly routes every Telegram user through the pairing flow when the policy is "pair". If you were running with an empty allowlist and "pair" (or default "deny"), upgrading will start enforcing the policy. Set unknown_user_policy: "allow" to restore the old “anyone can message” behavior. Discord and Slack already behaved correctly and are unchanged.

Policy Options

Which Policy Should I Choose?


CLI Fallback

When owner_user_id is not set, the bot replies to the requester:
The owner can then approve manually:
Where <channel_type> is one of: telegram, discord, slack.

Security: HMAC-signed Callbacks

Internals (PR #2108): Pairing approve/deny now dispatches through the generic InteractiveRegistry under the reserved pair namespace. The behavior, callback format, and HMAC verification are identical — but you can now register your own handlers under different namespaces (e.g. approval, menu) on the same adapter without conflicting. See Interactive Bot Actions.
All inline-button callbacks are cryptographically signed to prevent tampering:
  • Callback format: pair:{action}:{channel}:{user_id}:{code}:{sig}
  • Signature: First 8 hex chars of HMAC-SHA256(PRAISONAI_CALLBACK_SECRET, payload)
  • Verification: Tampered callback_data fails verification and is silently ignored + logged
Without PRAISONAI_CALLBACK_SECRET set in your environment, a random per-process secret is used and inline buttons stop working after bot restart. Always set this in production:

Platform-specific UI

Uses InlineKeyboardMarkup with ✅ Approve / ❌ Deny buttons. Callbacks are handled via CallbackQueryHandler that parses the signed callback_data and verifies the HMAC signature.What the owner sees:
Implementation: Telegram’s InlineKeyboardButton with callback_data containing the signed pairing payload. The {channel} field in the pair:{action}:{channel}:{user_id}:{code}:{sig} format contains the platform identifier (telegram), not the chat ID.
Uses discord.ui.View with success (green) and danger (red) button styles. Handled via button.callback method that verifies the HMAC signature in the custom_id.What the owner sees:
Implementation: Discord’s Button components in an Action Row with HMAC-signed custom_id values. The {channel} field in the callback format is the platform identifier (discord).
Uses Block Kit actions block with primary (blue) and danger (red) button styles. Handled via @app.action("pair_approve") and @app.action("pair_deny") decorators that verify the signature in the button’s value.What the owner sees:
Implementation: Slack Block Kit buttons with HMAC-signed values and dedicated action handlers. The {channel} field in the callback format is the platform identifier (slack).

Configuration Options

For the complete BotConfig options including unknown_user_policy and owner_user_id, see the canonical reference at Messaging Bots Configuration.

Common Patterns

Perfect for customer support or community bots where you want to vet new users.

Best Practices

Generate a strong secret and set it as an environment variable:
Without this, inline buttons stop working when your bot restarts.
Each platform has its own user ID format:
  • Telegram: Numeric ID (e.g., 123456789)
  • Discord: Snowflake ID (e.g., 123456789012345678)
  • Slack: User ID format (e.g., U1234ABCD)
Find your ID by messaging the bot directly and checking the logs, or use platform-specific methods.
If using unknown_user_policy="allow" for a public bot, protect yourself with:
Consider also implementing rate limiting at the platform level.
When you deny a pairing request, the code is consumed and cannot be retried. The user must send a new message to generate a fresh code. This prevents spam and ensures each approval decision is deliberate.

Pair a user with a non-empty --label (the canonical id) and StoreBackedIdentityResolver automatically unifies their session across every channel paired under the same label. No separate praisonai identity link calls needed. See Cross-Platform Sessions › StoreBackedIdentityResolver.

Messaging Bots

Complete bot configuration and setup

Bot Security

Security best practices for bots

Web-UI HTTP API Approval

HTTP API endpoints for web admin UI approval

Cross-Platform Sessions

Unified per-user sessions across platforms