Cloudflare Worker Telegram bot that monitors OKX P2P fiat-to-crypto buy prices. The default report is CNY -> USDT with a 1000 CNY spend amount, and admins can add custom monitors from Telegram.
- Hourly reports via Cloudflare Cron Triggers.
- Telegram webhook endpoint at
/telegram/webhook. - OKX P2P web data source matching the public market page behavior.
- Admin-only monitor mutations.
- KV-backed monitor registry.
- One-shot quotes, pair lookup, payment lookup, manual test, and manual cron trigger.
/help
/quote CNY USDT amount=3000 pay=aliPay,wxPay
/add CNY USDT amount=3000 pay=aliPay chat=admin,-100123 label=cny-usdt
/list
/remove <id>
/test <id>
/pairs CNY
/payments CNY USDT
chat=admin expands to ADMIN_CHAT_IDS. chat=here sends reports to the chat where the command was issued.
- Install dependencies:
npm install- Create a KV namespace:
npx wrangler kv namespace create MONITORS
npx wrangler kv namespace create MONITORS --preview-
Put the returned namespace IDs into
wrangler.toml. -
Set Worker secrets:
npx wrangler secret put TELEGRAM_BOT_TOKEN
npx wrangler secret put TELEGRAM_WEBHOOK_SECRET
npx wrangler secret put ADMIN_USER_IDS
npx wrangler secret put ADMIN_CHAT_IDS
npx wrangler secret put DEFAULT_TARGET_CHAT_IDS
npx wrangler secret put CRON_DEBUG_SECRETFor local development, copy .dev.vars.example to .dev.vars and fill in real values.
- Deploy:
npm run deploy- Register the Telegram webhook:
curl "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" \
-d "url=https://<your-worker>.<your-subdomain>.workers.dev/telegram/webhook" \
-d "secret_token=$TELEGRAM_WEBHOOK_SECRET"npm run devManual report trigger:
curl -X POST "http://127.0.0.1:8787/debug/run?secret=<CRON_DEBUG_SECRET>"Health check:
curl "http://127.0.0.1:8787/health"npm test
npm run typecheck- This uses OKX's current public web P2P endpoints, not a formally stable OKX public API.
- For user-facing
buybehavior, the OKX request usesside=sellbecause it fetches ads from merchants selling crypto to you. - If OKX returns unsupported market code
17007or no eligible ads, the bot reports that condition instead of failing the whole hourly run.