Bot implementation guide
This page maps the protocol to concrete code in node-backend. Use it when building or debugging a bot integration.
Quick start
- Read Bot framework, Authentication, and Protocol.
- Study
api/testBot.ts— the complete reference bot (dev stage only). - Reuse
lib/botVerify.tsandlib/botClient.tsin your deployment. - Register on dev via
create_bot, pointendpointat your HTTPS server, challenge the bot from the dev site.
Reference bot (api/testBot.ts)
Deployed as the testBot Lambda when testBotEnabled.dev is true in serverless.yml.
| Route | Handler | Purpose |
|---|---|---|
GET /testBot |
handlePing() |
Availability check |
POST /testBot |
handlePost() |
Signed challenge and move webhooks |
handlePost() flow:
- Read raw body string.
verifyBotRequest(rawBody, headers)fromlib/botVerify.ts.- Parse JSON; branch on
verb:challenge→ accept/reject based on test settings →200/400move→ return202, then async:pickMove()→submitBotMove()
pickMove() replays moves through GameFactory and plays the first legal move (or pass). Replace this with your engine.
Dev dashboard
test_bot_status and update_test_bot auth queries expose recent webhook events and settings (acceptChallenges, rejectMetaGames, movePolicy, moveDelayMs). These are not part of the production bot contract.
Reusable libraries
| Module | Use on | Purpose |
|---|---|---|
lib/botVerify.ts |
Your server | Verify AP webhook signatures |
lib/botClient.ts |
Your server | OAuth token cache + botQuery move submission |
lib/botOutbound.ts |
AP backend | Build payloads, sign, POST to bots |
lib/botSigning.ts |
AP backend | Ed25519 signing for outbound webhooks |
lib/botSecrets.ts |
AP backend | Cognito secret rotation |
lib/botCognito.ts |
AP backend | Create bot Cognito clients |
lib/botNames.ts |
AP backend | Display name reservation |
AP-side delivery pipeline
abstractplay.ts
newChallenge / submitMove / notifyRegisteredBotsTurn
→ enqueueBotOutbound({ type: 'challenge' | 'move', ... })
→ SQS BotOutboundQueue
→ utils/bot-outbound.ts handler
→ processBotChallengeMessage / processBotMoveMessage
→ postToBot() with signed body
Challenge acceptance triggers botRespondToChallenge() → respondedChallenge() in abstractplay.ts.
Adapting for production
- Host any HTTPS server — Lambda, Cloud Run, VPS, etc.
- Implement GET ping — return
200and{ "operational": true }. - Implement signed POST handler — verify signatures before parsing JSON.
- Challenge — return
200or400synchronously; no background work. - Move — return
202within the timeout (30s on AP'spostToBot); compute move asynchronously; callbotQuery. - Register with
create_bot; storeclientId/clientSecretsecurely. - Test on dev before creating a prod bot.
Environment variables (your bot)
| Variable | Purpose |
|---|---|
BOT_TOKEN_URL |
OAuth token endpoint for your stage |
BOT_OAUTH_SCOPE |
Scope string for client_credentials grant |
BOT_QUERY_URL |
Full URL to /botQuery for your stage |
AP_BOT_PUBLIC_KEY |
Optional override for signature verification |
The test bot Lambda also uses TEST_BOT_CLIENT_ID, TEST_BOT_CLIENT_SECRET, and ABSTRACT_PLAY_TABLE.
Environment variables (AP backend)
Set in serverless.yml: BOTPOOL_ID, BOT_TOKEN_URL, BOT_OAUTH_SCOPE, BOT_QUERY_URL, BOT_OUTBOUND_QUEUE_URL, OPENSSH_PRIVATE_KEY (signing key for outbound webhooks).
Troubleshooting
| Symptom | Check |
|---|---|
401 on botQuery before Lambda runs |
Token missing OAuth scope; compare BOT_OAUTH_SCOPE with API Gateway bot authorizer |
| Signature verification fails | Using parsed/re-serialized JSON instead of raw body |
| Challenge never accepted | Bot returned non-200/400; check BOT.lastStatusCode |
| Bot never moves | Bot did not return 202 on move webhook, or botQuery failed silently |
| Dev bot works, prod does not | Separate credentials and endpoints per stage |
Related
- Registration
- Protocol
- Bots subsystem — short overview
- Database schema —
BOT,BOTNAME