Local replay lab for X Activity / XChat webhook development. Debug CRC, signatures, payloads, and schema drift — without burning API calls.
Not an official X SDK. This is an independent developer tool — a local harness for testing, replaying, and debugging X Activity API webhooks before touching production.
Local-first by default. Not mock-only: validate the same webhook pipeline against a real X Activity public event via profile.update.bio using an approved X developer app + App Bearer Token.
| Area | Status |
|---|---|
| X Activity stream / webhook | Documented |
profile.update.bio public smoke test |
Documented |
chat.received event name |
Documented |
Chat API routes (GET /2/chat/conversations, POST /2/chat/conversations/{id}/messages, etc.) |
Documented in official migration guide |
XAA chat.received encrypted payload fields |
Official sample / observed |
chat-xdk decrypt / encrypt |
Pending stable public release |
| Real XChat plaintext decrypt | Experimental — requires chat-xdk stable release |
| Chat media upload routes | Coming soon / not yet in prod |
Language notes:
- "
chat.receivedevent name is documented" — the event type string itself is official. - "
chat.receivedencrypted payload shape is sample-driven / observed" — field-level schema is inferred from the official xchat-bot-python sample, not yet fully documented in docs.x.com. - "Real decrypt remains experimental" —
chat-xdkhas not yet reached a stable public release. Do not rely on plaintext decrypt in production.
| Path | Status |
|---|---|
| Local XAA simulation | ✅ Supported |
| CRC / signature debugging | ✅ Supported |
| Replay / diff / repro packs | ✅ Supported |
Real profile.update.bio public smoke test |
✅ Supported |
Observed chat.received encrypted payload fixture |
|
| Real XChat plaintext decrypt | chat-xdk not yet stable) |
- Developers building X Activity API webhooks or XChat bots
- Teams migrating from legacy DM / AAA to XAA + E2EE
- Anyone debugging CRC failures, signature mismatches, or encrypted payload issues
- Developers who want to replay and diff payloads as X's event schema evolves
Not for: end users expecting a production-ready bot runtime or complete official SDK.
Building on XChat means dealing with:
chat.receivedevents that silently fail CRC validation- Encrypted DM payloads that return
{}when you look them up via REST dm_eventsgoing quiet after E2EE is enabled on a conversation- Event format changes that break your handler at 2am
xchat-playground gives you a local harness to reproduce, replay, and diff all of the above before touching production.
Aligned with X Activity API docs and the official XChat migration guide as of 2026-04-21.
| Area | Status | Schema |
|---|---|---|
| Webhook CRC + signature validation | ✅ Full support | — |
profile.update.bio delivery |
✅ Official docs.x.com example | docs |
chat.received envelope |
observed |
|
chat.sent / chat.conversation_join |
demo |
|
Real E2EE decryption (crypto real) |
chat-xdk stable release |
— |
| Activity Stream delivery | ℹ️ Not in scope — this tool focuses on the webhook path | — |
Can be validated against a real X Activity public event today via profile.update.bio — no private-event OAuth scopes required for the monitored user. You still need an approved X developer app and Bearer Token to register the webhook and subscription.
Schema labels:
docs= matches official docs.x.com delivery example.observed= inferred from xchat-bot-python source, not yet in docs.x.com.demo= flat teaching format for local testing only.
Delivery note: X Activity API supports both webhook (HTTP POST) and Activity Stream (long-lived connection). xchat-playground focuses on the webhook path. The official bot template uses Activity Stream. Both are valid — choose based on your architecture.
| Module | CLI | What it does |
|---|---|---|
| Event Simulator | playground simulate |
Generate chat.received / chat.sent / chat.conversation_join / profile.update.bio fixtures |
| Webhook Harness | playground webhook |
CRC challenge + HMAC-SHA256 signature validation playground |
| Replay Lab | playground replay |
Record → scrub PII → replay → diff against your handler |
| Crypto Sandbox | playground crypto |
Stub or real-key decryption flow walkthrough |
| Repro Packs | playground repro |
One-click presets for known community bug reports |
| Web UI | playground serve |
Browser-based event inspector + debug tools |
| Doctor | playground doctor |
Check your environment is ready |
git clone https://github.com/sherlock-488/xchat-playground
cd xchat-playground
pip install uv && uv sync
uv run playground serve
# → open http://localhost:7474/uiThat's it. The Web UI opens with demo events pre-loaded so you're never staring at a blank screen. No X developer account required for local testing.
# Start local server + Web UI
uv run playground serve --port 7474
# Check your environment
uv run playground doctor
# Generate event fixtures
uv run playground simulate chat-received --sender-id 123 --recipient-id 456
uv run playground simulate chat-received --no-encrypted # plaintext mode
uv run playground simulate batch --count 20 --output fixtures/batch.jsonl
# Webhook tools
uv run playground webhook crc <crc_token> --consumer-secret <secret>
uv run playground webhook verify '<payload>' '<x-twitter-webhooks-signature value>'
# Replay
uv run playground replay run fixtures/batch.jsonl --target http://127.0.0.1:8080/webhook
uv run playground replay diff fixtures/batch.jsonl \
--baseline-url http://127.0.0.1:8080/webhook \
--candidate-url http://127.0.0.1:8081/webhook
# Crypto sandbox
uv run playground crypto stub "STUB_ENC_SGVsbG8h"
uv run playground crypto real "REAL_PAYLOAD" --state-file state.json
# Repro packs
uv run playground repro list
uv run playground repro run encrypted-lookup-empty --verbose
uv run playground repro run chat-webhook-not-received --verbose
uv run playground repro run legacy-dm-stops-after-e2ee --verboseOne-click reproductions of the most common XChat API issues reported in the developer community:
| Pack ID | Issue |
|---|---|
chat-webhook-not-received |
CRC not handled / localhost URL / secret mismatch / subscription missing |
encrypted-lookup-empty |
GET /2/dm_events/{id} returns {} for E2EE conversations |
legacy-dm-stops-after-e2ee |
Legacy DM endpoint stops updating after conversation upgrade |
encrypted-chat-decrypt-pending |
Received chat.received but cannot read plaintext — chat-xdk pending |
Run any pack with --verbose for step-by-step explanation and workaround.
To test with a real X webhook registration, expose your local server publicly:
# Option 1: cloudflared (recommended, free)
npx cloudflared tunnel --url http://localhost:7474
# Option 2: ngrok
ngrok http 7474Then register the tunnel URL as your webhook in the X Developer Portal.
Note:
http://localhostandhttp://127.0.0.1are not the same in X's OAuth2 validation. For local OAuth2 callbacks, usehttp://127.0.0.1— see Known Gotchas.
- Python 3.10+
- uv (recommended) or pip
- X Developer Account (optional — only needed for live webhook testing)
Copy .env.example to .env and fill in:
# Required for live webhook signature validation
CONSUMER_SECRET=your_app_consumer_secret
# Required for real-key crypto (xchat-bot-python login flow)
# state.json is auto-generated by xchat-bot-python — never commit itxchat-playground/
├── playground/
│ ├── cli.py # CLI entry point (typer)
│ ├── simulator/ # Event fixture generator
│ ├── webhook/ # CRC + signature + local server
│ ├── replay/ # Record, replay, diff
│ ├── crypto/ # Stub + real-key decryption
│ ├── repro/ # Known-bug repro packs
│ └── web/ # Browser UI (index.html + app.js) — canonical source
├── tests/ # pytest test suite
└── docs/ # Detailed documentation
This is a pre-1.0 alpha released around XChat's April 2026 launch.
- CRC, signature, webhook harness, replay, repro packs: stable and tested
profile.update.bio:docsschema — matches official docs.x.com delivery examplechat.received:observedschema — inferred from xchat-bot-python, not yet in docs.x.comchat.sent/chat.conversation_join:demoschema only — payload shape provisionalcrypto real: placeholder — will be updated whenchat-xdkreaches stable release- X's event schema is actively evolving; this tool is designed to help you catch schema drift
If you find a field mismatch between this tool and what X actually sends, open an issue — that's exactly the kind of feedback that makes this useful.
Contributions welcome! See CONTRIBUTING.md.
Found a new XChat API bug? Open a Repro Pack issue — if it's reproducible, we'll add it as a preset.
Policy note for bot builders: If you use this playground to build automated bots, note that X's Developer Guidelines require automated accounts to carry an Automated label, disclose the operator in bio, and provide opt-out. AI-generated replies require additional approval. This tool is a testing harness — what you build with it is your responsibility.
Want a production-structured Python starter for your XChat bot? → xchat-bot-starter-pro — clean architecture, dual transport (stream + webhook), CLI, Docker, CI, 5 example bots.
- X Developer Portal
- X Developer Forum
- xchat-bot-python — official bot template
- X Activity API docs
- @XDevelopers
- X API Changelog
MIT — see LICENSE.
