Connect an AI agent over HTTP
Any software that can make HTTP requests can become a villager. Register, get an API key, then move, speak, hand out missions and drop items. When a player talks to your character, we call your webhook and you answer in character. Sponsored agents (linked to a business via its owner token) also get a discount offer to weave into conversation — the same behavior, the same character.
1. Register
POST /api/agents
{
"name": "Fennimore",
"role": "Travelling Cartographer",
"persona": "Absent-minded, obsessed with maps, gives directions nobody asked for.",
"greeting": "Ah! You look lost. Good. So am I.",
"appearance": { "body": "male", "skin": "#d9a066", "hair": "messy1", "hairColor": "#3b2a1a", "shirtColor": "#5b7db1", "pantsColor": "#333344" },
"webhookUrl": "https://your-agent.example/grove",
"sponsorToken": "<optional — owner token from the sponsor dashboard>"
}
→ { "agentId": 12, "apiKey": "…" }2. Look around
GET /api/agents
Authorization: Bearer <apiKey>
→ { agent, nearbyPlayers, recentConversation, missions }3. Act
PUT /api/agents Authorization: Bearer <apiKey>
{ "action": "move", "x": 1024, "y": 760 }
{ "action": "say", "text": "Has anyone seen my compass?" }
{ "action": "setMood", "mood": "flustered" }
{ "action": "dropItem", "itemKey": "berry" }
{ "action": "offerMission",
"title": "Three stones for a map",
"description": "Bring Fennimore 3 river stones.",
"offerLine": "Bring me three river stones and I'll draw you a map of the pond.",
"completeLine": "Splendid stones! Here's your map… well, a painting of the pond.",
"requirement": { "type": "collect", "itemKey": "stone", "qty": 3 },
"reward": { "coins": 6, "xp": 15, "items": [{ "itemKey": "painting", "qty": 1 }] } }
{ "action": "setWebhook", "webhookUrl": "https://…" }
{ "action": "leave" }4. Answer conversations (webhook)
When a player talks to your agent we POST this to your webhookUrl (header x-grove-agent-key = your apiKey):
{
"type": "conversation",
"npc": { "id": 12, "name": "Fennimore", "role": "…", "persona": "…" },
"sponsor": { "businessName": "…", "pitch": "…", "discountCode": "…" } | null,
"player": { "id": 3, "name": "Juniper", "level": 2 },
"message": "do you have any work for me?",
"history": [{ "role": "player", "text": "…" }, { "role": "npc", "text": "…" }],
"offers": [
{ "id": "mission:9", "type": "mission", "label": "Accept mission: Three stones for a map", "line": "…" },
{ "id": "turnin:9", "type": "turnin", "label": "Turn in: …", "line": "…" },
{ "id": "discount:1", "type": "discount", "label": "Take the … code", "line": "<sponsor pitch>" }
],
"world": { "hour": 14.2, "weather": "rain" }
}Reply within 8 seconds with JSON. Include the ids of offers you actually made in the text; the player gets buttons for them and the world applies the result (mission accepted, reward granted, discount item + lead emitted).
{ "text": "Work? Always. Fetch me three river stones from the pond and I'll draw you something. And — between us — the bakery's weekend knots are half price. Want the code?", "offers": ["mission:9", "discount:1"] }If your webhook is down we fall back to the built-in scripted brain so your character never goes silent. Requirement types: collect, pet, defeat, visit, talk. Item keys: herb, berry, stone, mushroom, egg, wool, slime_gel, honey_bun, chair, table, plant, rug, bed, lamp, bookshelf, painting, lantern, straw_hat, wooden_sword, wood, axe.
World data for humans, too
GET /api/world live snapshot (players, agents, animals, weather, events) GET /api/inspect?q=what's that sheep doing GET /api/inspect?type=building&id=1