Telegram-based advertising and influencer marketplace platform. Advertisers create campaigns with budgets and targeting, while channel owners (influencers) monetize their Telegram channels by publishing sponsored content.
This project is a submission for the Ad Marketplace Contest by Builders.
Try it out: @wild_post_bot
For influencers: add @wildpost_employer as an admin to your Telegram channel with all permissions to enable stats fetching and auto-posting.
The platform has two modes that users can switch between:
- Influencer mode — Manage your Telegram channels, view stats, submit creatives, and withdraw earnings
- Advertiser mode — Create and manage advertisers, set up campaigns with budgets and targeting, review creatives, and track deal progress
To switch between modes, long-press the Influencer or Advertiser button in the bottom navigation menu. The selected mode is persisted in local storage.
Wildpost is a monorepo with 5 services connected via a shared Docker network (ad_net):
| Service | Description | README |
|---|---|---|
/api |
FastAPI backend (REST API, JWT auth) | api/README.md |
/bot |
Telegram bot (aiogram 3.x) | bot/README.md |
/workers |
Celery background task workers | workers/README.md |
/client |
Next.js frontend (Telegram Mini App) | client/README.md |
/db |
PostgreSQL + PgBouncer + HAProxy | db/README.md |
- Users interact via the Telegram bot or the Mini App (Next.js frontend)
- The FastAPI backend handles REST endpoints with JWT authentication
- PostgreSQL stores all data, accessed via SQLAlchemy 2.0 (async) through PgBouncer
- Celery workers process background jobs (posting, payments, verification) via RabbitMQ
- Telethon (Telegram client library) handles posting to channels and fetching stats
- TON blockchain handles payments and withdrawals
| Layer | Technology |
|---|---|
| API | FastAPI, Uvicorn, Gunicorn |
| Bot | aiogram 3.x, Python 3.13 |
| Workers | Celery, RabbitMQ |
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS |
| Database | PostgreSQL 16, SQLAlchemy 2.0, Alembic, PgBouncer |
| Caching | Redis 7 |
| Blockchain | TON (tonutils, pytoniq_core) |
| Telegram Client | Telethon (session-based) |
| Monitoring | Prometheus, Loki, Tempo, Grafana, cAdvisor |
| Reverse Proxy | Nginx with Cloudflare |
| Decision | Why |
|---|---|
| Telethon user bot | The Telegram Bot API cannot fetch broadcast channel statistics (GetBroadcastStatsRequest) or publish posts to channels on behalf of a user account. A Telethon MTProto client (@wildpost_employer) is required for stats fetching, auto-publishing, and post verification. |
| Model duplication across services | Each service (/api, /bot, /workers) maintains its own SQLAlchemy models. This enables independent deployment without shared package dependencies and avoids import chain issues across different runtimes (uvicorn vs aiogram vs celery). |
| Per-queue Celery workers | Each task type runs in its own worker with a dedicated queue. This provides isolation (a slow stats fetch won't block payment checking), independent scaling, and prevents Telethon session conflicts (one session per worker). |
| PgBouncer + HAProxy | Connection pooling is essential for async workers that open/close connections frequently. PgBouncer pools PostgreSQL connections in transaction mode, HAProxy adds health checking and load balancing. |
| TON blockchain | Aligns with the Telegram ecosystem. TON provides fast, low-fee transactions suitable for micropayments in an ad marketplace. |
| JWT from Telegram initData | Telegram Mini Apps provide initData with a cryptographic signature. The API validates this signature using the bot token, checks auth_date to prevent replay attacks, and issues a short-lived JWT — secure authentication without passwords. |
| Per-deal deposit addresses | Each deal gets a unique TON deposit address. This isolates funds per deal for clean escrow tracking, automated on-chain payment verification, and auditable refund paths. |
| Admin re-verification on financial ops | Bot admin status is re-checked via the Bot API (getChatMember) before processing withdrawals, ensuring the bot still has permissions in the channel before releasing funds. |
| Deal auto-expiration | Deals that stall at any stage are automatically expired/cancelled by a cron task. Pre-payment deals expire after 24h, post-payment deals are cancelled after 48-72h and feed into the refund pipeline. |
- Add a channel — Send your channel link to the bot. The bot resolves the channel and stores its Telegram ID. You must add
@wildpost_employeras an admin with all permissions for stats fetching and auto-posting to work. - Channel verification — The bot verifies it has admin access. Channels with 500+ subscribers automatically get detailed statistics fetched every hour by the
fetch_channels_stats_cronworker. - Browse campaigns — In influencer mode, browse active campaigns from advertisers. Filter by category, language, budget, and subscriber requirements.
- Apply to a campaign — Submit an application with your channel and proposed price. The advertiser reviews your channel stats and decides.
- Application approved → Deal created — Once approved, a deal is created. Wait for the advertiser to pay.
- Submit a creative — After the advertiser pays, you submit a creative matching the campaign requirements (text, media, inline buttons). If a creative template exists, the rules are enforced (max text length, allowed media types, etc.).
- Creative review — The advertiser reviews your submission:
- Approved — your creative is scheduled for auto-publishing
- Changes requested — revise and resubmit
- Rejected — submit a new creative version
- Auto-publishing — The approved creative is automatically published to your channel at the scheduled time via Telethon. No manual action needed.
- Keep the post live — The post must remain published for the agreed minimum duration (default 24h). The
verify_posts_cronworker will check that it still exists and the bot is still an admin. - Get paid — After successful verification, your channel balance is credited with the deal amount.
- Withdraw earnings — Request a withdrawal to your TON wallet via the bot. A 5% platform fee is deducted. The bot shows a full breakdown (amount, fee, net payout) at every step. The
process_channel_withdrawals_cronworker sends the net amount to your wallet.
- Create an advertiser — Register your advertiser profile via Mini App. You become the owner with full permissions. Optionally invite managers with granular permissions.
- Create a campaign — Define targeting (channel categories, languages, subscriber range, avg views), set a budget in TON, choose preferred creative types (POST, STORY, REPOST), and optionally attach a creative template with content requirements.
- Activate the campaign — Campaign status:
DRAFT → ACTIVE. Active campaigns become visible to channel owners. - Receive applications — Channel owners browse active campaigns and apply. You see each applicant's channel stats and can approve or reject applications.
- Approve an application — An approved application creates a deal between you and the channel. The deal enters
PENDING_PAYMENTstatus with an agreed price. - Pay for the deal — You pay the deal amount in TON to a unique deposit address. The
check_deal_payments_cronworker verifies the transaction on-chain. Once confirmed, the deal moves toCREATIVE_PENDING. - Review the creative — The channel owner submits a creative (text, media, buttons). You can:
- Approve — the creative moves to
CREATIVE_APPROVEDand gets scheduled for auto-publishing - Request changes — the channel owner revises and resubmits
- Reject — the creative is rejected and the channel owner can submit a new version
- Approve — the creative moves to
- Post is published — The Celery worker auto-publishes the approved creative to the channel via Telethon at the scheduled time.
- Verification — After the minimum duration (default 24h), the
verify_posts_cronworker checks that the post still exists and the bot is still a channel admin. - Deal completion — If verification passes, the deal is marked
COMPLETEDand the channel owner's balance is credited. If verification fails and funds have been swept to the hot wallet, a refund is processed back to your wallet.
DRAFT → PENDING_APPROVAL → APPROVED → PENDING_PAYMENT → PAID →
CREATIVE_PENDING → CREATIVE_SUBMITTED → CREATIVE_APPROVED →
SCHEDULED → PUBLISHED → (verification) → COMPLETED / REFUNDED / CANCELLED
| Status | Description |
|---|---|
DRAFT |
Deal created, not yet submitted for approval |
PENDING_APPROVAL |
Awaiting advertiser approval |
APPROVED |
Advertiser approved the deal |
PENDING_PAYMENT |
Waiting for TON payment from advertiser |
PAID |
Payment confirmed on-chain |
CREATIVE_PENDING |
Awaiting creative submission from channel owner |
CREATIVE_SUBMITTED |
Creative submitted, awaiting advertiser review |
CREATIVE_APPROVED |
Advertiser approved the creative |
CREATIVE_REJECTED |
Advertiser rejected the creative |
SCHEDULED |
Creative scheduled for auto-publishing |
PUBLISHED |
Post published to the channel |
VERIFICATION_PENDING |
Awaiting post verification after min duration |
COMPLETED |
Post verified, channel owner credited |
DISPUTED |
Deal is under dispute |
REFUNDED |
Funds refunded to advertiser (failed verification, funds were swept) |
CANCELLED |
Deal cancelled (failed verification, funds not yet swept) |
EXPIRED |
Deal expired without completion |
Both advertisers and channels support a multi-user management system. Owners can invite other Telegram users as managers with granular permissions.
| Permission | Description |
|---|---|
can_manage_campaigns |
Create, edit, and manage campaigns |
can_manage_managers |
Invite or remove other managers |
can_edit_advertiser |
Edit advertiser profile details |
| Permission | Description |
|---|---|
can_manage_deals |
Accept/reject deals, submit creatives, manage scheduling |
can_manage_pricing |
Set and update channel pricing |
can_withdraw |
Initiate balance withdrawals to a TON wallet |
can_manage_managers |
Invite or remove other managers |
The user who creates an advertiser or adds a channel becomes the owner with all permissions. Managers are soft-deleted (removed_at) when removed, preserving audit history.
When a deal is approved and paid, the channel owner submits a creative — the actual content to be published. Creatives go through a review workflow (DRAFT → SUBMITTED → APPROVED / CHANGES_REQUESTED / REJECTED).
| Type | Description |
|---|---|
POST |
Standard channel post with text, media, and inline buttons |
STORY |
Telegram channel story with configurable duration |
REPOST |
Forward/repost of an existing message |
Advertisers can attach creative templates to campaigns to define content requirements for channel owners:
- Max text length — character limit for the creative text
- Allowed media types — which media formats are accepted (photo, video, etc.)
- Max media count — how many media files can be attached
- Buttons — whether inline buttons are allowed and how many
- Link preview — whether URL previews are enabled
- Story duration — duration in seconds for story-type creatives
- Prohibited content and additional notes — guidelines for the channel owner
Each creative is linked to a template (if one exists for the campaign), and the template rules are enforced during submission.
Adding channel and fetching stats (as influencer) | Creating an advertiser and campaign (as advertiser)
Check result here (the post time might not be correct for testing purposes)
- Docker and Docker Compose
- Node.js 18+ (for client development)
- Python 3.11+ (for API/workers) or Python 3.13+ (for bot)
- uv (bot dependency management)
- Poetry (API/workers dependency management)
- Telegram Bot Token (from @BotFather)
- Telegram API credentials (
API_ID,API_HASHfrom https://my.telegram.org) - TON API key (from TON API)
All services share the ad_net Docker bridge network. Deploy in this order: db → api → bot → workers → client.
See each service's README for detailed deployment instructions.
-
Channel stats require 500+ subscribers — Telegram's API only exposes detailed channel statistics for channels with at least 500 subscribers.
-
TON payments only — All payments and withdrawals are processed exclusively via the TON blockchain.
-
Single pending withdrawal per channel — A channel can only have one pending withdrawal at a time; the previous one must complete or fail first.
-
Telethon session limits — Each Telethon session can only be used by one worker at a time; concurrent access will cause session conflicts.
-
Adjustable 5% platform fee on withdrawals — A flat 5% fee is deducted from all channel owner withdrawals. Future: tiered fee structure based on volume (lower fees for high-volume channels).
-
Minimum withdrawal amount — Channel owners must have at least 0.5 TON balance to initiate a withdrawal.
-
User bot must be channel admin — The user bot (
@wildpost_employer) must be added as an admin with all permissions to each channel for stats fetching and auto-posting. Admin status is re-verified before financial operations. -
User bot (Telethon) is central to the flow — The Telegram Bot API does not support fetching channel statistics or publishing posts on behalf of a channel. A Telethon-based user bot is used for stats fetching, auto-publishing, and post verification.
-
Post verification timing — Posts are verified only after the agreed minimum duration (default 24 hours) has elapsed.
-
Model duplication — SQLAlchemy models are duplicated across
/api,/bot, and/workersservices. Future: shared model package published as an internal dependency. -
Seed phrases stored in plain text — Currently, seed phrases are stored in environment variables in plain text. Future: implement encryption at rest using a key management service.





