We’ve been building Jai as a small AI assistant that runs inside our WordPress site without turning the backend into a chaos monster. The first step was wiring a clean REST endpoint in WordPress. We set up a custom route (WP REST API) that accepts a user prompt, performs basic validation, and then forwards the request to Pollinations. Keeping the AI call server-side let us hide credentials and control behavior centrally.
On the frontend, Jai needed a "presence." We didn’t want a heavy video pipeline, so we drew a simple talking face on a canvas and animated it based on the response lifecycle. The animation is intentionally lightweight: when the REST call starts, the face "breathes," and as tokens arrive we update a mouth curve and blink timings. Nothing magical—just a few state changes tied to async fetch events—so it stays stable even when the network is slow.
The part that saved us from runaway usage was rate limiting. We implemented per-IP daily quotas using WordPress transients. After each successful request, we increment a counter stored under a key that includes the client IP. If the counter reaches the daily limit, the endpoint returns a friendly message telling the visitor to come back tomorrow.
The real debugging story came from our Pollinations integration. Initially we used the older endpoint: text.pollinations.ai/openai. It looked fine on paper, then requests started failing with a 402 response. After digging into it, we confirmed the old endpoint was being deprecated for authenticated key requests. We switched to gen.pollinations.ai/v1/chat/completions and updated the request format to match. After that change, the same WordPress REST call that previously returned 402 began returning valid completions again.
Net result: a reliable WordPress REST boundary, a canvas-based talking UI, strict per-IP daily limits via transients, and an integration that survives provider endpoint changes without turning our logs into a guessing game.