Getting started
Using the API from LSL
Your in-world scripts can drive a bot with llHTTPRequest. Drop this helper into a script and call lifebots("command", [name, value, …]).
lifebots-helper.lsl
// LifeBots helper - put your details here
string API = "https://api.lifebots.cloud/api/bot.html";
string APIKEY = "YOUR_API_KEY";
string BOTNAME = "Joe Resident";
string SECRET = "bot-secret-123";
// Send a command. params is a list of name/value pairs.
key lifebots(string action, list params)
{
string body = "action=" + action
+ "&apikey=" + llEscapeURL(APIKEY)
+ "&botname=" + llEscapeURL(BOTNAME)
+ "&secret=" + llEscapeURL(SECRET)
+ "&dataType=json";
integer i;
for (i = 0; i < llGetListLength(params); i += 2)
body += "&" + llList2String(params, i) + "=" + llEscapeURL(llList2String(params, i + 1));
return llHTTPRequest(API, [HTTP_METHOD, "POST",
HTTP_MIMETYPE, "application/x-www-form-urlencoded"], body);
}
default
{
touch_start(integer n)
{
// Invite whoever touched me to the group
lifebots("group_invite", [
"groupuuid", "b3f87fed-0470-4a7e-b035-100000000000",
"avatar", (string)llDetectedKey(0)
]);
}
http_response(key id, integer status, list meta, string body)
{
if (llJsonGetValue(body, ["result"]) != "OK")
llOwnerSay("LifeBots: " + llJsonGetValue(body, ["resulttext"]));
}
}Tips
- Send form-encoded bodies, and run every value through
llEscapeURL— names and messages contain spaces. - Ask for
dataType=jsonand read fields withllJsonGetValue. - Second Life throttles
llHTTPRequestper object (roughly 25 requests in 20 seconds). Queue work instead of firing in a loop. - Responses longer than 2 KB are cut off by LSL unless you raise
HTTP_BODY_MAXLENGTH(up to 16 KB). - Keep credentials safe — see Authentication.
Receiving bot events in-world
An object can get its own URL with llRequestURL and register it as a webhook, so the bot tells your script about IMs, invites or payments. See Webhooks & events for every event.
receive-events.lsl (add the lifebots() helper above)
// Receive bot events in-world (needs a free URL on the parcel)
key gUrlRequest;
default
{
state_entry() { gUrlRequest = llRequestURL(); }
changed(integer c)
{
// URLs are lost when the region restarts or the object moves
if (c & (CHANGED_REGION_START | CHANGED_REGION | CHANGED_TELEPORT))
gUrlRequest = llRequestURL();
}
http_request(key id, string method, string body)
{
if (id == gUrlRequest && method == URL_REQUEST_GRANTED)
{
// Register (or re-register) the new URL with the bot
lifebots("set_http_callback", ["url", body, "events", "instant_message"]);
return;
}
llHTTPResponse(id, 200, "OK"); // answer fast - within 10 seconds
if (llJsonGetValue(body, ["action"]) == "instant_message")
llOwnerSay(llJsonGetValue(body, ["speaker_name"]) + ": " + llJsonGetValue(body, ["message"]));
}
} In-world URLs change whenever the region restarts or the object moves, so re-register on every new URL as above. Registering a new URL does not remove the old one — remove it with
set_http_callback and operation=remove, or it is dropped automatically after 24 hours of failures.